@rubytech/create-realagent 1.0.654 → 1.0.655

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-realagent",
3
- "version": "1.0.654",
3
+ "version": "1.0.655",
4
4
  "description": "Install Real Agent — Built for agents. By agents.",
5
5
  "bin": {
6
6
  "create-realagent": "./dist/index.js"
@@ -318,7 +318,7 @@ systemd-run --user --unit=maxy-tunnel-restart-<nonce>.service --on-active=3s --c
318
318
  /bin/systemctl --user restart "${BRAND}.service"
319
319
  ```
320
320
 
321
- The script then emits `[setup-tunnel] step=service-restart-dispatched` and `step=service-restart-armed exit=0` in the per-conversation stream log so operators see exactly when the restart was scheduled, exits 0, and the transient timer fires from outside the service's cgroup — semantically identical to this manual runbook's `systemctl --user restart`.
321
+ The script then emits `[script:setup-tunnel] step=service-restart-dispatched` and `step=service-restart-armed exit=0` in the per-conversation stream log so operators see exactly when the restart was scheduled, exits 0, and the transient timer fires from outside the service's cgroup — semantically identical to this manual runbook's `systemctl --user restart`. (The `script:` prefix is Task 605's chat-surface namespace — see `_stream-log.sh` header.)
322
322
 
323
323
  When walking through manually you do **not** need `systemd-run` — your SSH shell already lives in a separate user-scope cgroup (`user@<uid>.service`), so the direct `systemctl restart` does not kill the caller. The script's extra indirection only matters when the caller *is* the service being restarted.
324
324
 
@@ -7,27 +7,38 @@
7
7
  # per-conversation file the chat UI's server-side tailer reads.
8
8
  #
9
9
  # Contract (read by platform/ui/app/lib/script-stream-tailer.ts tailer and
10
- # .docs/platform.md):
11
- # [<ISO-ts>] [<scope>] <kv …>
12
- # [<ISO-ts>] [<scope>:<subprocess-tag>] <raw line>
13
- # Canonical regex — SCRIPT_STREAM_RE at platform/ui/app/lib/script-stream-tailer.ts:51:
14
- # ^\[([^\]]+)\] \[([a-z][a-z0-9-]*)((?::[a-z0-9:_-]+)?)\] (.*)$
10
+ # .docs/web-chat.md):
11
+ # [<ISO-ts>] [script:<scope>] <kv …>
12
+ # [<ISO-ts>] [script:<scope>:<subprocess-tag>] <raw line>
13
+ # Canonical regex — SCRIPT_STREAM_RE at platform/ui/app/lib/script-stream-tailer.ts:
14
+ # ^\[([^\]]+)\] \[script:([a-z][a-z0-9-]*)((?::[a-z0-9:_-]+)?)\] (.*)$
15
+ # The literal `script:` prefix is the chat-surface namespace (Task 605). It
16
+ # separates chat-surface emitters from log-file-only scopes (`[mcp:<server>]`
17
+ # from mcp-stderr-tee, `[init]` / `[api-wait-*]` / `[mcp-init-error]` /
18
+ # `[subproc-stderr]` / `[compaction-*]` from claude-agent.ts) which share
19
+ # the same per-conversation stream log but must NOT reach the chat UI.
20
+ # Callers of phase_line / tee_subprocess / tee_subprocess_capture pass the
21
+ # bare scope (e.g. `setup-tunnel`, `list-cf-domains`, `reset-tunnel:cloudflared`);
22
+ # these helpers prepend `script:` to the stream-log write. Stderr mirrors
23
+ # stay unprefixed — stderr is for direct-SSH operators and route-handler
24
+ # `reason=<enum>` regex, not the chat-surface contract.
15
25
  # <scope> is any `[a-z][a-z0-9-]*` token (Task 592 generalised from the
16
26
  # pre-592 enum `setup-tunnel|reset-tunnel`, which silently filtered out the
17
27
  # `[list-cf-domains]` lines Task 589 emitted). <subprocess-tag> may contain
18
- # lowercase, digits, `-`, `_`, `:`. Adding a new <scope> requires no edit to
19
- # the regex — the shape is the only contract. Any prefix-shape change must
20
- # be made on both sides (this helper + script-stream-tailer.ts) atomically.
28
+ # lowercase, digits, `-`, `_`, `:`. Adding a new chat-surface scope requires
29
+ # no edit to the regex — the shape is the only contract. Any prefix-shape
30
+ # change must be made on both sides (this helper + script-stream-tailer.ts)
31
+ # atomically.
21
32
  #
22
33
  # Inner layers (e.g. a node/python helper a .sh wrapper spawns — Task 598's
23
34
  # `list-cf-domains.sh` → `list-cf-domains.ts` pattern) must write phase lines
24
- # directly to STREAM_LOG_PATH with the same prefix shape: stderr alone is
25
- # silently discarded by runFormSpawn on exit 0. The build-gate
26
- # `platform/ui/scripts/check-stream-log-contract.mjs` (Task 600) enforces this
27
- # by rejecting any .sh under `platform/plugins/*/scripts/` that sources this
28
- # helper and invokes an interpreter subprocess whose target does not pair a
29
- # STREAM_LOG_PATH env read with an append/write call. Opt out per invocation
30
- # with `# stream-log-contract: stderr-only (reason: <prose>)`.
35
+ # directly to STREAM_LOG_PATH with the same prefix shape (including the
36
+ # `script:` namespace): stderr alone is silently discarded by runFormSpawn on
37
+ # exit 0. The build-gate `platform/ui/scripts/check-stream-log-contract.mjs`
38
+ # (Task 600) enforces this by rejecting any .sh under `platform/plugins/*/scripts/`
39
+ # that sources this helper and invokes an interpreter subprocess whose target
40
+ # does not pair a STREAM_LOG_PATH env read with an append/write call. Opt out
41
+ # per invocation with `# stream-log-contract: stderr-only (reason: <prose>)`.
31
42
 
32
43
  # Exit 1 loudly with the variable name and the invoking scope so direct-SSH
33
44
  # invocations fail fast and the operator reads exactly what to set. No
@@ -56,12 +67,16 @@ stream_log_ts() {
56
67
  # tool's stderr capture carries it. Both paths matter: the stream log is
57
68
  # the live tailer surface; stderr is the exit-time Bash-tool surface.
58
69
  #
70
+ # The stream-log write carries the `script:` chat-surface namespace (Task 605);
71
+ # the stderr mirror stays unprefixed because stderr is read by direct-SSH
72
+ # operators and the route-handler `reason=<enum>` regex, not the chat UI.
73
+ #
59
74
  # Usage: phase_line <scope> <key=value …>
60
75
  phase_line() {
61
76
  local scope="$1"; shift
62
77
  local ts
63
78
  ts="$(stream_log_ts)"
64
- printf '[%s] [%s] %s\n' "${ts}" "${scope}" "$*" >> "${STREAM_LOG_PATH}"
79
+ printf '[%s] [script:%s] %s\n' "${ts}" "${scope}" "$*" >> "${STREAM_LOG_PATH}"
65
80
  printf '[%s] %s\n' "${scope}" "$*" >&2
66
81
  }
67
82
 
@@ -97,7 +112,7 @@ tee_subprocess() {
97
112
  "${buf_prefix[@]}" "$@" 2>&1 | while IFS= read -r line; do
98
113
  local ts
99
114
  ts="$(stream_log_ts)"
100
- printf '[%s] [%s] %s\n' "${ts}" "${tag}" "${line}" >> "${STREAM_LOG_PATH}"
115
+ printf '[%s] [script:%s] %s\n' "${ts}" "${tag}" "${line}" >> "${STREAM_LOG_PATH}"
101
116
  printf '%s\n' "${line}" >&2
102
117
  done
103
118
  return "${PIPESTATUS[0]}"
@@ -132,7 +147,7 @@ tee_subprocess_capture() {
132
147
  "${buf_prefix[@]}" "$@" 2>&1 | while IFS= read -r line; do
133
148
  local ts
134
149
  ts="$(stream_log_ts)"
135
- printf '[%s] [%s] %s\n' "${ts}" "${tag}" "${line}" >> "${STREAM_LOG_PATH}"
150
+ printf '[%s] [script:%s] %s\n' "${ts}" "${tag}" "${line}" >> "${STREAM_LOG_PATH}"
136
151
  printf '%s\n' "${line}"
137
152
  done
138
153
  return "${PIPESTATUS[0]}"
@@ -91,15 +91,18 @@ function logPhase(line: string): void {
91
91
  // Stream log: direct write by the TS helper (not via wrapper tee) so phase
92
92
  // lines reach the per-conversation file the Task 592 tailer reads, even on
93
93
  // exit 0 where runFormSpawn discards `result.stderr`. Format parity with
94
- // `_stream-log.sh phase_line`: `[<ISO-ts>] [<scope>] <content>\n`, asserted
95
- // by the vitest regression under platform/ui/__tests__. Sync append so the
94
+ // `_stream-log.sh phase_line`: `[<ISO-ts>] [script:<scope>] <content>\n`
95
+ // the `script:` prefix is Task 605's chat-surface namespace so the line
96
+ // passes the tightened tailer regex (`[mcp:*]` / `[init]` / `[api-wait-*]`
97
+ // lines in the same file are excluded by construction). Asserted by the
98
+ // vitest regression under platform/ui/__tests__. Sync append so the
96
99
  // terminal `phase=script-exit code=0 count=N` lands before process exit.
97
100
  const streamLogPath = process.env.STREAM_LOG_PATH;
98
101
  if (!streamLogPath || streamLogWriteFailed) return;
99
102
  try {
100
103
  appendFileSync(
101
104
  streamLogPath,
102
- `[${new Date().toISOString()}] [list-cf-domains] ${line}\n`,
105
+ `[${new Date().toISOString()}] [script:list-cf-domains] ${line}\n`,
103
106
  );
104
107
  } catch (err) {
105
108
  streamLogWriteFailed = true;
@@ -65,7 +65,8 @@ mkdir -p "${CFG_DIR}"
65
65
  # Control flow, rewritten per Task 556:
66
66
  # 1. CDP precheck on 127.0.0.1:9222 — loud failure if Chromium isn't up.
67
67
  # 2. Spawn cloudflared with stdout+stderr teed line-by-line to
68
- # $STREAM_LOG_PATH with prefix [setup-tunnel:cloudflared].
68
+ # $STREAM_LOG_PATH with prefix [script:setup-tunnel:cloudflared]
69
+ # (Task 605's chat-surface namespace — see _stream-log.sh header).
69
70
  # 3. Extract the authorize URL with a tolerant regex as it streams.
70
71
  # 4. Drive the VNC Chromium to that URL via CDP `PUT /json/new?<url>`.
71
72
  # 5. Wait for ~/.cloudflared/cert.pem to land with bounded timeout.
@@ -113,7 +114,7 @@ if [ ! -f "${CFG_DIR}/cert.pem" ]; then
113
114
  --origincert "${CFG_DIR}/cert.pem" tunnel login 2>&1 |
114
115
  while IFS= read -r line; do
115
116
  ts="$(stream_log_ts)"
116
- printf '[%s] [setup-tunnel:cloudflared] %s\n' "${ts}" "${line}" >> "${STREAM_LOG_PATH}"
117
+ printf '[%s] [script:setup-tunnel:cloudflared] %s\n' "${ts}" "${line}" >> "${STREAM_LOG_PATH}"
117
118
  printf '%s\n' "${line}" >&2
118
119
  printf '%s\n' "${line}" > "${LAST_LINE_FILE}"
119
120
  if [ ! -s "${URL_FILE}" ]; then
@@ -418,8 +419,8 @@ for H in "${HOSTNAMES[@]}"; do
418
419
  phase_line setup-tunnel step=route-dns hostname="${H}" tunnel_id="${TUNNEL_ID}"
419
420
  ROUTE_LOG="$(mktemp -t maxy-route-dns.XXXXXX)"
420
421
  # tee_subprocess_capture streams cloudflared's combined stdout+stderr
421
- # into STREAM_LOG_PATH line-by-line with the [setup-tunnel:cloudflared]
422
- # tag (live-tailable) AND passes the same output through this shell's
422
+ # into STREAM_LOG_PATH line-by-line with the [script:setup-tunnel:cloudflared]
423
+ # tag (live-tailable — Task 605 chat-surface namespace) AND passes the same output through this shell's
423
424
  # stdout so the `> "${ROUTE_LOG}"` redirection can capture it for the
424
425
  # failure-path phase_line. Exit code is cloudflared's PIPESTATUS[0].
425
426
  if tee_subprocess_capture setup-tunnel:cloudflared -- \
@@ -11330,7 +11330,7 @@ function defaultRules() {
11330
11330
  name: "setup-tunnel.sh failed to persist step-7 completion",
11331
11331
  type: "silent-catch",
11332
11332
  logSource: "any",
11333
- pattern: "\\[setup-tunnel\\] step=onboarding-persist result=error",
11333
+ pattern: "\\[script:setup-tunnel\\] step=onboarding-persist result=error",
11334
11334
  thresholdCount: 0,
11335
11335
  thresholdWindowMinutes: 0,
11336
11336
  suggestedAction: "[Task 562] setup-tunnel.sh could not persist step-7 completion before arming the service restart. Read the `reason` field on the failing phase line: `fs-flag-dir-failed` means `${ACCOUNT_DIR}/onboarding/` is not writable (chmod issue or disk full); `fs-flag-write-failed` means the flag file itself could not be written. Without the flag, the next admin session will re-ask the Cloudflare question the user just answered. Recovery: fix the permission/disk issue, then either re-run `~/setup-tunnel.sh` (the flag-write is idempotent) or call `onboarding-complete-step` with step 7 from the admin chat to mark step 7 complete explicitly."
@@ -18090,7 +18090,7 @@ import * as childProcess from "child_process";
18090
18090
  import { appendFileSync as appendFileSync6, createReadStream as createReadStream2, mkdirSync as mkdirSync12, statSync as statSync8 } from "fs";
18091
18091
  import { dirname as dirname7 } from "path";
18092
18092
  import { StringDecoder as StringDecoder2 } from "string_decoder";
18093
- var SCRIPT_STREAM_RE = /^\[([^\]]+)\] \[([a-z][a-z0-9-]*)((?::[a-z0-9:_-]+)?)\] (.*)$/;
18093
+ var SCRIPT_STREAM_RE = /^\[([^\]]+)\] \[script:([a-z][a-z0-9-]*)((?::[a-z0-9:_-]+)?)\] (.*)$/;
18094
18094
  function parseLine(line) {
18095
18095
  const m = line.match(SCRIPT_STREAM_RE);
18096
18096
  if (!m) return void 0;
@@ -18185,6 +18185,11 @@ function startScriptStreamTailer(opts) {
18185
18185
  }
18186
18186
  var SCOPE_TOKEN_RE = /^[a-z][a-z0-9-]*$/;
18187
18187
  function writeRouteMilestone(streamLogPath, scope, line) {
18188
+ if (scope.startsWith("script:")) {
18189
+ throw new Error(
18190
+ `writeRouteMilestone: scope "${scope}" must not start with "script:" \u2014 the helper prepends it (Task 605)`
18191
+ );
18192
+ }
18188
18193
  if (!SCOPE_TOKEN_RE.test(scope)) {
18189
18194
  throw new Error(
18190
18195
  `writeRouteMilestone: scope "${scope}" must match [a-z][a-z0-9-]* \u2014 the tailer regex won't match otherwise`
@@ -18193,7 +18198,7 @@ function writeRouteMilestone(streamLogPath, scope, line) {
18193
18198
  const ts = (/* @__PURE__ */ new Date()).toISOString();
18194
18199
  try {
18195
18200
  mkdirSync12(dirname7(streamLogPath), { recursive: true });
18196
- appendFileSync6(streamLogPath, `[${ts}] [${scope}] ${line}
18201
+ appendFileSync6(streamLogPath, `[${ts}] [script:${scope}] ${line}
18197
18202
  `);
18198
18203
  } catch (err) {
18199
18204
  console.error(