aibroker 0.36.0 → 0.38.0

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.
@@ -0,0 +1,100 @@
1
+ /**
2
+ * daemon/dialogs.ts — the modal nobody is there to click.
3
+ *
4
+ * WHY THIS EXISTS. Everything else that watches a managed session watches its
5
+ * TERMINAL: the pane's text, the transcript, the manager's own history. A macOS
6
+ * modal belongs to a different process and appears in none of them, so a
7
+ * session can sit blocked behind one for hours while every signal reads
8
+ * healthy — working, goal armed, screen unchanged for a plausible reason. An
9
+ * operator discovered this the only way it can be discovered without this file:
10
+ * by finding the dialog by hand and clicking it a hundred times.
11
+ *
12
+ * WHAT IT WILL AND WILL NOT PRESS. Only prompts of the "may this app do the
13
+ * obvious thing it was just asked to do" kind, from a fixed list of system
14
+ * agents, with a fixed list of button titles. Anything asking for a credential
15
+ * is excluded by name and by construction: SecurityAgent is not on the list,
16
+ * and no button title here is one that a password sheet offers. The rule is
17
+ * that this may only re-consent to something the operator already set in
18
+ * motion; it may never grant something new.
19
+ */
20
+ import { runAppleScript } from "../adapters/iterm/core.js";
21
+ import { log } from "../core/log.js";
22
+ /**
23
+ * The agents allowed to have their dialogs answered.
24
+ *
25
+ * Short and closed on purpose. Each is a system process whose entire job is
26
+ * asking permission for an action a user already initiated — opening an app
27
+ * that was just built, letting one app drive another that it has been driving
28
+ * all evening. SecurityAgent is deliberately ABSENT: that is the one that asks
29
+ * for passwords and disk access, and nothing should ever answer it but a
30
+ * person.
31
+ */
32
+ const ANSWERABLE = ["CoreServicesUIAgent", "UserNotificationCenter"];
33
+ /**
34
+ * Buttons that mean "yes, as already intended".
35
+ *
36
+ * Matched exactly, never as a substring — "Don't Allow" contains "Allow", and a
37
+ * substring match would turn a refusal into consent. Order matters: the first
38
+ * title found on the dialog is the one pressed.
39
+ */
40
+ const SAFE_BUTTONS = ["Open", "Allow", "OK"];
41
+ const LIST_SCRIPT = `
42
+ tell application "System Events"
43
+ set out to ""
44
+ repeat with pname in {${ANSWERABLE.map((p) => `"${p}"`).join(", ")}}
45
+ try
46
+ tell process pname
47
+ repeat with w in windows
48
+ set btns to ""
49
+ try
50
+ repeat with b in buttons of w
51
+ set btns to btns & (title of b) & "~"
52
+ end repeat
53
+ end try
54
+ set out to out & (pname as string) & "|" & (name of w) & "|" & btns & linefeed
55
+ end repeat
56
+ end tell
57
+ end try
58
+ end repeat
59
+ return out
60
+ end tell`;
61
+ /** Every dialog currently on screen that belongs to an answerable agent. */
62
+ export function listDialogs() {
63
+ const raw = runAppleScript(LIST_SCRIPT, 10_000);
64
+ if (!raw)
65
+ return [];
66
+ return raw
67
+ .split("\n")
68
+ .map((line) => line.trim())
69
+ .filter(Boolean)
70
+ .map((line) => {
71
+ const [process, title, btns] = line.split("|");
72
+ return {
73
+ process: process ?? "",
74
+ title: title ?? "",
75
+ buttons: (btns ?? "").split("~").map((b) => b.trim()).filter(Boolean),
76
+ };
77
+ })
78
+ .filter((d) => ANSWERABLE.includes(d.process));
79
+ }
80
+ /**
81
+ * Answer one dialog, and say which button was pressed.
82
+ *
83
+ * Returns null when nothing was pressed, which includes the case of a dialog
84
+ * offering none of the safe titles — an unrecognised prompt is left alone and
85
+ * reported rather than guessed at, because the whole value of a closed list is
86
+ * lost the moment something falls back to "press the default".
87
+ */
88
+ export function answerDialog(d) {
89
+ const button = SAFE_BUTTONS.find((b) => d.buttons.includes(b));
90
+ if (!button)
91
+ return null;
92
+ const script = `tell application "System Events" to tell process "${d.process}" to click button "${button}" of window 1`;
93
+ const ok = runAppleScript(script, 10_000);
94
+ if (ok === null) {
95
+ log(`[dialogs] could not press "${button}" on ${d.process}`);
96
+ return null;
97
+ }
98
+ return button;
99
+ }
100
+ //# sourceMappingURL=dialogs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialogs.js","sourceRoot":"","sources":["../../src/daemon/dialogs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAErC;;;;;;;;;GASG;AACH,MAAM,UAAU,GAAG,CAAC,qBAAqB,EAAE,wBAAwB,CAAC,CAAC;AAErE;;;;;;GAMG;AACH,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;AAS7C,MAAM,WAAW,GAAG;;;0BAGM,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;SAgB3D,CAAC;AAEV,4EAA4E;AAC5E,MAAM,UAAU,WAAW;IACzB,MAAM,GAAG,GAAG,cAAc,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAChD,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,OAAO,GAAG;SACP,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/C,OAAO;YACL,OAAO,EAAE,OAAO,IAAI,EAAE;YACtB,KAAK,EAAE,KAAK,IAAI,EAAE;YAClB,OAAO,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;SACtE,CAAC;IACJ,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AACnD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,CAAa;IACxC,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,MAAM,GAAG,qDAAqD,CAAC,CAAC,OAAO,sBAAsB,MAAM,eAAe,CAAC;IACzH,MAAM,EAAE,GAAG,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;QAChB,GAAG,CAAC,8BAA8B,MAAM,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7D,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -36,6 +36,56 @@ export interface ManagedSession {
36
36
  lastChangeAt: number;
37
37
  lastHash: string;
38
38
  paused: boolean;
39
+ /**
40
+ * The file the session hands over in — a TEMPLATE, not a fixed path.
41
+ *
42
+ * `{date}`, `{yyyy}`, `{mm}` and `{dd}` are expanded when the file is used
43
+ * rather than when it is set, because a session that runs for days outlives
44
+ * the day it was started on. A literal date written into the path was right
45
+ * for one evening and then quietly wrong: the request kept naming yesterday's
46
+ * file, and the drift grows by a day every day.
47
+ */
48
+ handoverFile?: string;
49
+ /** The path actually asked for, so a date rolling over mid-episode cannot
50
+ * make the change check compare two different files. */
51
+ handoverAskedPath?: string;
52
+ /**
53
+ * Clear the session after the handover, rather than leaving it to compact.
54
+ * OFF unless asked for — see the rollover block for what changed this.
55
+ */
56
+ clearAfterHandover?: boolean;
57
+ /** Consecutive armings typed but never seen to land. Bounded — see ARM_ATTEMPTS. */
58
+ armFails?: number;
59
+ /** When a handover was last obtained, so it is not demanded every tick. */
60
+ handoverDoneAt?: number;
61
+ /** The context reading when it was obtained, so "how much work since" is
62
+ * answerable — a handover ages by work done, not by the clock. */
63
+ handoverDoneK?: number;
64
+ /** When a handover was asked for, so a silent session can be given up on. */
65
+ handoverAskedAt?: number;
66
+ /** What that file looked like when asked, so "changed" is measured not claimed. */
67
+ handoverWas?: string;
68
+ /** When a clear was typed, so it is never typed twice WITHIN one rollover. */
69
+ clearTypedAt?: number;
70
+ /**
71
+ * When a clear was typed that has never been seen to land — ACROSS rollovers.
72
+ *
73
+ * The per-rollover guard was not enough and the gap was ugly: a session whose
74
+ * context stays high keeps qualifying for rollover, so each new attempt typed
75
+ * its own clear, and a session in a turn long enough to execute none of them
76
+ * accumulated a queue of them. They would then all fire in sequence, the
77
+ * first against the session they were meant for and the rest against whatever
78
+ * fresh session had started since — which is the exact "wipe the session that
79
+ * just started" failure the single-clear rule existed to prevent, reached by
80
+ * going around it rather than through it.
81
+ *
82
+ * So the invariant is stronger than "one clear per rollover": at most one
83
+ * unconfirmed clear per session, ever, and no new rollover may begin while
84
+ * one is outstanding.
85
+ */
86
+ clearPendingSince?: number;
87
+ /** Context before the clear, so "it landed" is measured against something. */
88
+ contextAtClear?: number;
39
89
  /** The pane, so the process and thence the checkout can be found again. */
40
90
  tty?: string;
41
91
  /** Screen work forbidden — the operator has the machine. Survives re-arming. */
@@ -47,6 +97,37 @@ export interface ManagedSession {
47
97
  handsWas?: boolean;
48
98
  startedAt: number;
49
99
  }
100
+ /**
101
+ * Is there text sitting unsent in the session's prompt?
102
+ *
103
+ * TYPING ON TOP OF IT DESTROYS IT. The manager pastes into the same input line
104
+ * a person types into, and it sends a backspace first to escape vi normal
105
+ * mode — so an objective armed over half-typed text eats a character of that
106
+ * text and then runs the two together as one prompt. The operator's sentence
107
+ * and the standing objective arrive merged and mangled, and neither does what
108
+ * it meant to.
109
+ *
110
+ * This never bit while nobody was at the keyboard, which is exactly the kind of
111
+ * assumption that holds until an operator sits down at seven in the morning and
112
+ * starts a sentence.
113
+ *
114
+ * The live input line is the one enclosed by the terminal's rules at the foot
115
+ * of the pane, not the `❯` lines further up — those are scrollback, commands
116
+ * that already ran. So the rule immediately above it is what identifies it.
117
+ */
118
+ export declare function promptUnsentText(content: string): string | null;
119
+ export declare function promptHasUnsentText(content: string): boolean;
120
+ /**
121
+ * Expand the date tokens in a handover path, against the clock right now.
122
+ *
123
+ * Deliberately resolved at the moment of use. A managed session is meant to
124
+ * outlive the day it started on, so any date fixed at the moment the path was
125
+ * SET is a date that will be wrong by morning — and wrong in the quietest way,
126
+ * since the file it names still exists and still opens.
127
+ *
128
+ * Exported for the tests, which is also where the accepted tokens are pinned.
129
+ */
130
+ export declare function resolveHandoverPath(template: string, at?: Date): string;
50
131
  /**
51
132
  * Resolve a session by whatever the caller knows — its id, or its name.
52
133
  *
@@ -57,6 +138,20 @@ export declare function resolveSession(idOrName: string): {
57
138
  sessionId: string;
58
139
  name: string;
59
140
  } | null;
141
+ /**
142
+ * Collapse text to a single line, for anything about to be TYPED at a prompt.
143
+ *
144
+ * At a prompt a newline is the submit key, so a multi-line objective does not
145
+ * arrive as a long goal — it arrives as a short one, followed by its own
146
+ * remainder as a second, contextless prompt, and the session acts on both. The
147
+ * damage is silent: what was sent looks right in the state file and wrong only
148
+ * on screen.
149
+ *
150
+ * Applied at the point text becomes keystrokes rather than at each point text
151
+ * is set, so it covers every route in — shell heredoc, MCP call, appended
152
+ * text, operator notes — including the ones added later.
153
+ */
154
+ export declare function oneLine(text: string): string;
60
155
  export declare function startManagerLoop(): void;
61
156
  export interface ManageResult {
62
157
  ok: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"manage.d.ts","sourceRoot":"","sources":["../../src/daemon/manage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAyDH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,4DAA4D;IAC5D,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,2EAA2E;IAC3E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;kFAC8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AA6KD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAY3F;AAyaD,wBAAgB,gBAAgB,IAAI,IAAI,CASvC;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAoSjG"}
1
+ {"version":3,"file":"manage.d.ts","sourceRoot":"","sources":["../../src/daemon/manage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AA+LH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,4DAA4D;IAC5D,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;6DACyD;IACzD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;uEACmE;IACnE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;;;;;;;;OAeG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2EAA2E;IAC3E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;kFAC8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAyLD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgB/D;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,GAAE,IAAiB,GAAG,MAAM,CAUnF;AA6KD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAY3F;AA8PD;;;;;;;;;;;;GAYG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5C;AAgmBD,wBAAgB,gBAAgB,IAAI,IAAI,CASvC;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CA8ZjG"}