@codeagentswarm/cas-cloud 0.0.12 → 0.0.16
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/dist/antigravity-mcp-launcher.js +35 -8
- package/dist/cas.js +485 -197
- package/dist/mcp-stdio-server.js +35 -8
- package/dist/templates/antigravity-md-titles-section.md +3 -3
- package/dist/templates/codex-md-titles-section.md +3 -3
- package/dist/templates/grok-md-titles-section.md +16 -19
- package/dist/templates/kimi-md-titles-section.md +11 -12
- package/dist/templates/opencode-md-titles-section.md +3 -3
- package/package.json +1 -1
package/dist/cas.js
CHANGED
|
@@ -14842,33 +14842,30 @@ CodeAgentSwarm shows two different things per agent:
|
|
|
14842
14842
|
the context stays clear at a glance \u2014 name the feature, NOT a low-level step or file,
|
|
14843
14843
|
and NOT a work PHASE (testing, e2e, validating, reviewing, deploying). Running the e2e
|
|
14844
14844
|
suite for a settings redesign is titled "Settings Redesign", never "Settings E2E Tests".
|
|
14845
|
-
|
|
14846
|
-
and it
|
|
14847
|
-
|
|
14845
|
+
Derive it from the **first user request** that established this conversation's
|
|
14846
|
+
functionality and set it ONCE per conversation. It stays stable across follow-ups,
|
|
14847
|
+
new turns, tasks, reviews, tests, validation, finishing, and context compaction.
|
|
14848
14848
|
2. **Current activity** = the product-focused step you are doing RIGHT NOW. Example:
|
|
14849
14849
|
"Implementing the analytics tracking backend". It is shown only when the user hovers
|
|
14850
14850
|
the agent, and it accumulates as the activity log behind the clock button.
|
|
14851
14851
|
|
|
14852
14852
|
## \u{1F4E2} THE RULE
|
|
14853
14853
|
|
|
14854
|
-
**\u{1F6A6} FIRST ACTION
|
|
14855
|
-
|
|
14856
|
-
the user manually renamed the agent the app keeps their name (a manual rename always wins
|
|
14857
|
-
over an MCP title). Never leave an agent with no meaningful title.
|
|
14854
|
+
**\u{1F6A6} FIRST ACTION in a new conversation:** set the GENERAL title from the first user
|
|
14855
|
+
request. On later turns, do NOT call \`set_terminal_title\`; update activity instead.
|
|
14858
14856
|
|
|
14859
14857
|
**\u{1F4CD} ALWAYS leave a CURRENT SUMMARY before acting.** Right after the title, call
|
|
14860
14858
|
\`update_terminal_activity\` with your first product-focused step, BEFORE running any other
|
|
14861
14859
|
tool. If an agent has no activity yet, set one before you do anything else \u2014 so at every
|
|
14862
14860
|
moment the user can see what each agent is doing. Never start working with no activity set.
|
|
14863
14861
|
|
|
14864
|
-
**
|
|
14862
|
+
**First request \u2192 set the title ONCE. Every turn \u2192 update the ACTIVITY.**
|
|
14865
14863
|
|
|
14866
|
-
- \u2705
|
|
14867
|
-
|
|
14868
|
-
expands the feature), or to REPLACE it when the topic changes RADICALLY.
|
|
14864
|
+
- \u2705 Keep the title from the first user request. Refining, extending, fixing, reviewing,
|
|
14865
|
+
validating, or finishing that request changes the activity, not the title.
|
|
14869
14866
|
- \u2705 RADICAL topic change \u2192 NEW general title, MANDATORY. When the user switches this
|
|
14870
14867
|
agent to a completely different topic (e.g. from "Minimize Agents" to preparing
|
|
14871
|
-
a release), call \`set_terminal_title\` again with
|
|
14868
|
+
a release), call \`set_terminal_title\` again with \`replace_existing=true\`. Updating only the
|
|
14872
14869
|
activity and leaving the old title is WRONG: the tab would keep describing work that
|
|
14873
14870
|
is no longer happening.
|
|
14874
14871
|
- \u2705 Update the activity every time your focus moves to a new step. This is what the user
|
|
@@ -14882,7 +14879,7 @@ the app's own static UI stays in English; these agent-written labels follow the
|
|
|
14882
14879
|
|
|
14883
14880
|
**\u{1F527} THE TWO TOOLS:**
|
|
14884
14881
|
\`\`\`
|
|
14885
|
-
# 1) ONCE
|
|
14882
|
+
# 1) ONCE on the conversation's first request - the sticky tab title
|
|
14886
14883
|
mcp__codeagentswarm-tasks__set_terminal_title(
|
|
14887
14884
|
title="Promo Video",
|
|
14888
14885
|
long_title="Promotional video for the Twitter launch"
|
|
@@ -14903,9 +14900,8 @@ mcp__codeagentswarm-tasks__update_terminal_activity(
|
|
|
14903
14900
|
in the tab. \`long_title\` is the **GOAL**: one sentence on what this agent is FOR \u2014 the
|
|
14904
14901
|
outcome the work aims at, not the step you are on. The user reads it in the hover under
|
|
14905
14902
|
the title, labelled GOAL, and it is the ONLY place that answers "why does this agent
|
|
14906
|
-
exist"; six words cannot carry that.
|
|
14907
|
-
|
|
14908
|
-
single step here.
|
|
14903
|
+
exist"; six words cannot carry that. Repeated calls preserve the first title. Pass
|
|
14904
|
+
\`replace_existing=true\` only after the user pivots to completely different functionality.
|
|
14909
14905
|
\`\`\`
|
|
14910
14906
|
\u2705 title="Orden notificaci\xF3n"
|
|
14911
14907
|
long_title="Que las notificaciones no salgan antes de que cambie el status del agente"
|
|
@@ -14931,7 +14927,7 @@ mcp__codeagentswarm-tasks__update_terminal_activity(
|
|
|
14931
14927
|
1. find_related_active_tasks(...) \u2190 Check first
|
|
14932
14928
|
2. create_task(...) \u2190 If needed
|
|
14933
14929
|
3. start_task(task_id=123)
|
|
14934
|
-
4. set_terminal_title( \u2190
|
|
14930
|
+
4. set_terminal_title( \u2190 only if this conversation has no title
|
|
14935
14931
|
title="Minimize Agents",
|
|
14936
14932
|
long_title="Add the ability to minimize and restore agents"
|
|
14937
14933
|
)
|
|
@@ -14940,7 +14936,7 @@ mcp__codeagentswarm-tasks__update_terminal_activity(
|
|
|
14940
14936
|
7. ...keep calling update_terminal_activity as your focus moves to new steps...
|
|
14941
14937
|
\`\`\`
|
|
14942
14938
|
|
|
14943
|
-
**\u{1F6A8} CRITICAL:**
|
|
14939
|
+
**\u{1F6A8} CRITICAL:** starting another task in the same conversation does not justify retitling it.
|
|
14944
14940
|
|
|
14945
14941
|
### \u2705 WITHOUT A TASK (research/investigation):
|
|
14946
14942
|
\`\`\`
|
|
@@ -14959,13 +14955,10 @@ update_terminal_activity(activity="Implementing restore-from-minimized")
|
|
|
14959
14955
|
update_terminal_activity(activity="Persisting minimized state across restarts")
|
|
14960
14956
|
\`\`\`
|
|
14961
14957
|
|
|
14962
|
-
### \u2705 THE GOAL
|
|
14958
|
+
### \u2705 THE ORIGINAL GOAL EXPANDS \u2192 keep the title and update ACTIVITY:
|
|
14963
14959
|
\`\`\`
|
|
14964
|
-
# The user expanded the feature
|
|
14965
|
-
|
|
14966
|
-
title="Minimize & Restore",
|
|
14967
|
-
long_title="Minimize agents and restore them later from a tray"
|
|
14968
|
-
)
|
|
14960
|
+
# The user expanded the same feature; the first title remains "Minimize Agents":
|
|
14961
|
+
update_terminal_activity(activity="Adding restore from the tray")
|
|
14969
14962
|
\`\`\`
|
|
14970
14963
|
|
|
14971
14964
|
### \u2705 RADICAL TOPIC CHANGE \u2192 set a NEW general title (mandatory):
|
|
@@ -14974,7 +14967,8 @@ set_terminal_title(
|
|
|
14974
14967
|
User: "leave that, now let's prepare the release notes"
|
|
14975
14968
|
set_terminal_title(
|
|
14976
14969
|
title="Release Notes",
|
|
14977
|
-
long_title="Preparing the release notes for the next version"
|
|
14970
|
+
long_title="Preparing the release notes for the next version",
|
|
14971
|
+
replace_existing=true
|
|
14978
14972
|
)
|
|
14979
14973
|
update_terminal_activity(activity="Drafting the release notes")
|
|
14980
14974
|
# \u274C WRONG: calling only update_terminal_activity here \u2014 the tab would still
|
|
@@ -14983,9 +14977,8 @@ update_terminal_activity(activity="Drafting the release notes")
|
|
|
14983
14977
|
|
|
14984
14978
|
## \u26A0\uFE0F WHEN TO USE WHICH
|
|
14985
14979
|
|
|
14986
|
-
- **General title (set_terminal_title):** once
|
|
14987
|
-
|
|
14988
|
-
session \u2014 but NEVER leave a stale title on an agent that moved to another topic.
|
|
14980
|
+
- **General title (set_terminal_title):** once per conversation from the first request.
|
|
14981
|
+
Replace only after a radical functionality pivot, with \`replace_existing=true\`.
|
|
14989
14982
|
- **Current activity (update_terminal_activity):** every time you move to a new product
|
|
14990
14983
|
step. Call it freely - it never disturbs the tab.
|
|
14991
14984
|
|
|
@@ -15063,14 +15056,14 @@ update_terminal_activity(activity="Investigating the output handler cost") \u
|
|
|
15063
15056
|
**Bad 3 - Never setting a general title:**
|
|
15064
15057
|
\`\`\`
|
|
15065
15058
|
# Only calling update_terminal_activity, so the tab never gets a product label.
|
|
15066
|
-
\u2705
|
|
15059
|
+
\u2705 Set the title ONCE from the first user request so the tab is meaningful.
|
|
15067
15060
|
\`\`\`
|
|
15068
15061
|
|
|
15069
15062
|
**Bad 4 - Radical topic change but the title never changes:**
|
|
15070
15063
|
\`\`\`
|
|
15071
15064
|
# Title: "Promo Video". The user then says: "now let's debug the login crash"
|
|
15072
15065
|
update_terminal_activity(activity="Debugging the login crash") \u2190 \u274C tab still says "Promo Video"
|
|
15073
|
-
\u2705 set_terminal_title(title="Login Crash", long_title="Debugging the crash when logging in")
|
|
15066
|
+
\u2705 set_terminal_title(title="Login Crash", long_title="Debugging the crash when logging in", replace_existing=true)
|
|
15074
15067
|
\u2705 update_terminal_activity(activity="Reproducing the login crash")
|
|
15075
15068
|
\`\`\`
|
|
15076
15069
|
|
|
@@ -15111,22 +15104,21 @@ Rules:
|
|
|
15111
15104
|
|
|
15112
15105
|
` : ""}## \u{1F6A8} FINAL REMINDER
|
|
15113
15106
|
|
|
15114
|
-
- Set the **general title AND
|
|
15115
|
-
|
|
15116
|
-
radically \u2014 never leave a stale title.
|
|
15107
|
+
- Set the **general title AND GOAL once per conversation**, from the first user request.
|
|
15108
|
+
Follow-ups never retitle; a radical functionality pivot uses \`replace_existing=true\`.
|
|
15117
15109
|
- Keep the **current activity** flowing with \`update_terminal_activity\` (product-level),
|
|
15118
15110
|
one short sentence per step.
|
|
15119
15111
|
${includeStatus ? `- Keep the **status badge** honest with \`set_terminal_status\` at every phase change.
|
|
15120
15112
|
` : ""}- The tab should stay stable; the hover + clock-button log carry the detail.
|
|
15121
15113
|
|
|
15122
15114
|
**MEMORIZE:**
|
|
15123
|
-
${includeStatus ? `1. **
|
|
15115
|
+
${includeStatus ? `1. **First request \u2192 \`set_terminal_title(title, long_title)\` once + \`set_terminal_status(status="working")\`**
|
|
15124
15116
|
2. **New step \u2192 \`update_terminal_activity\` (product step)**
|
|
15125
15117
|
3. **Phase changed (waiting / testing / done) \u2192 \`set_terminal_status\`**
|
|
15126
|
-
4. **
|
|
15127
|
-
5. **\u{1F3C1} Finishing \u2192 final \`update_terminal_activity\` summary + \`set_terminal_status\` \u2192 \`complete_task\`**` : `1. **
|
|
15118
|
+
4. **Radical functionality pivot \u2192 \`set_terminal_title(..., replace_existing=true)\`**
|
|
15119
|
+
5. **\u{1F3C1} Finishing \u2192 final \`update_terminal_activity\` summary + \`set_terminal_status\` \u2192 \`complete_task\`**` : `1. **First request \u2192 \`set_terminal_title(title, long_title)\` once**
|
|
15128
15120
|
2. **New step \u2192 \`update_terminal_activity\` (product step)**
|
|
15129
|
-
3. **
|
|
15121
|
+
3. **Radical functionality pivot \u2192 \`set_terminal_title(..., replace_existing=true)\`**
|
|
15130
15122
|
4. **\u{1F3C1} Finishing \u2192 final \`update_terminal_activity\` summary \u2192 \`complete_task\`**`}
|
|
15131
15123
|
|
|
15132
15124
|
### \u{1F4DD} Task Plan Management
|
|
@@ -15374,8 +15366,9 @@ Avoid token limits:
|
|
|
15374
15366
|
- Creating new? \u2192 YES
|
|
15375
15367
|
|
|
15376
15368
|
**Agent Title?**
|
|
15377
|
-
-
|
|
15378
|
-
-
|
|
15369
|
+
- Set it from the first user request, once per conversation
|
|
15370
|
+
- Follow-up work changes activity, never the title
|
|
15371
|
+
- Radical functionality pivot \u2192 replace with \`replace_existing=true\`
|
|
15379
15372
|
|
|
15380
15373
|
**Task Continuation?**
|
|
15381
15374
|
- Same work <24h \u2192 Continue
|
|
@@ -15416,33 +15409,30 @@ CodeAgentSwarm shows two different things per agent:
|
|
|
15416
15409
|
the context stays clear at a glance \u2014 name the feature, NOT a low-level step or file,
|
|
15417
15410
|
and NOT a work PHASE (testing, e2e, validating, reviewing, deploying). Running the e2e
|
|
15418
15411
|
suite for a settings redesign is titled "Settings Redesign", never "Settings E2E Tests".
|
|
15419
|
-
|
|
15420
|
-
and it
|
|
15421
|
-
|
|
15412
|
+
Derive it from the **first user request** that established this conversation's
|
|
15413
|
+
functionality and set it ONCE per conversation. It stays stable across follow-ups,
|
|
15414
|
+
new turns, tasks, reviews, tests, validation, finishing, and context compaction.
|
|
15422
15415
|
2. **Current activity** = the product-focused step you are doing RIGHT NOW. Example:
|
|
15423
15416
|
"Implementing the analytics tracking backend". It is shown only when the user hovers
|
|
15424
15417
|
the agent, and it accumulates as the activity log behind the clock button.
|
|
15425
15418
|
|
|
15426
15419
|
## \u{1F4E2} THE RULE
|
|
15427
15420
|
|
|
15428
|
-
**\u{1F6A6} FIRST ACTION
|
|
15429
|
-
|
|
15430
|
-
the user manually renamed the agent the app keeps their name (a manual rename always wins
|
|
15431
|
-
over an MCP title). Never leave an agent with no meaningful title.
|
|
15421
|
+
**\u{1F6A6} FIRST ACTION in a new conversation:** set the GENERAL title from the first user
|
|
15422
|
+
request. On later turns, do NOT call \`set_terminal_title\`; update activity instead.
|
|
15432
15423
|
|
|
15433
15424
|
**\u{1F4CD} ALWAYS leave a CURRENT SUMMARY before acting.** Right after the title, call
|
|
15434
15425
|
\`update_terminal_activity\` with your first product-focused step, BEFORE running any other
|
|
15435
15426
|
tool. If an agent has no activity yet, set one before you do anything else \u2014 so at every
|
|
15436
15427
|
moment the user can see what each agent is doing. Never start working with no activity set.
|
|
15437
15428
|
|
|
15438
|
-
**
|
|
15429
|
+
**First request \u2192 set the title ONCE. Every turn \u2192 update the ACTIVITY.**
|
|
15439
15430
|
|
|
15440
|
-
- \u2705
|
|
15441
|
-
|
|
15442
|
-
expands the feature), or to REPLACE it when the topic changes RADICALLY.
|
|
15431
|
+
- \u2705 Keep the title from the first user request. Refining, extending, fixing, reviewing,
|
|
15432
|
+
validating, or finishing that request changes the activity, not the title.
|
|
15443
15433
|
- \u2705 RADICAL topic change \u2192 NEW general title, MANDATORY. When the user switches this
|
|
15444
15434
|
agent to a completely different topic (e.g. from "Minimize Agents" to preparing
|
|
15445
|
-
a release), call \`set_terminal_title\` again with
|
|
15435
|
+
a release), call \`set_terminal_title\` again with \`replace_existing=true\`. Updating only the
|
|
15446
15436
|
activity and leaving the old title is WRONG: the tab would keep describing work that
|
|
15447
15437
|
is no longer happening.
|
|
15448
15438
|
- \u2705 Update the activity every time your focus moves to a new step. This is what the user
|
|
@@ -15456,7 +15446,7 @@ the app's own static UI stays in English; these agent-written labels follow the
|
|
|
15456
15446
|
|
|
15457
15447
|
**\u{1F527} THE TWO TOOLS:**
|
|
15458
15448
|
\`\`\`
|
|
15459
|
-
# 1) ONCE
|
|
15449
|
+
# 1) ONCE on the conversation's first request - the sticky tab title
|
|
15460
15450
|
mcp__codeagentswarm-tasks__set_terminal_title(
|
|
15461
15451
|
title="Promo Video",
|
|
15462
15452
|
long_title="Promotional video for the Twitter launch"
|
|
@@ -15477,9 +15467,8 @@ mcp__codeagentswarm-tasks__update_terminal_activity(
|
|
|
15477
15467
|
in the tab. \`long_title\` is the **GOAL**: one sentence on what this agent is FOR \u2014 the
|
|
15478
15468
|
outcome the work aims at, not the step you are on. The user reads it in the hover under
|
|
15479
15469
|
the title, labelled GOAL, and it is the ONLY place that answers "why does this agent
|
|
15480
|
-
exist"; six words cannot carry that.
|
|
15481
|
-
|
|
15482
|
-
single step here.
|
|
15470
|
+
exist"; six words cannot carry that. Repeated calls preserve the first title. Pass
|
|
15471
|
+
\`replace_existing=true\` only after the user pivots to completely different functionality.
|
|
15483
15472
|
\`\`\`
|
|
15484
15473
|
\u2705 title="Orden notificaci\xF3n"
|
|
15485
15474
|
long_title="Que las notificaciones no salgan antes de que cambie el status del agente"
|
|
@@ -15498,9 +15487,9 @@ mcp__codeagentswarm-tasks__update_terminal_activity(
|
|
|
15498
15487
|
|
|
15499
15488
|
## \u{1F3AF} WORKFLOW
|
|
15500
15489
|
|
|
15501
|
-
### \u2705
|
|
15490
|
+
### \u2705 ON THE CONVERSATION'S FIRST REQUEST:
|
|
15502
15491
|
\`\`\`
|
|
15503
|
-
1. set_terminal_title( \u2190
|
|
15492
|
+
1. set_terminal_title( \u2190 once per conversation
|
|
15504
15493
|
title="Minimize Agents",
|
|
15505
15494
|
long_title="Add the ability to minimize and restore agents"
|
|
15506
15495
|
)
|
|
@@ -15515,13 +15504,10 @@ update_terminal_activity(activity="Implementing restore-from-minimized")
|
|
|
15515
15504
|
update_terminal_activity(activity="Persisting minimized state across restarts")
|
|
15516
15505
|
\`\`\`
|
|
15517
15506
|
|
|
15518
|
-
### \u2705 THE GOAL
|
|
15507
|
+
### \u2705 THE ORIGINAL GOAL EXPANDS \u2192 keep the title and update ACTIVITY:
|
|
15519
15508
|
\`\`\`
|
|
15520
|
-
# The user expanded the feature
|
|
15521
|
-
|
|
15522
|
-
title="Minimize & Restore",
|
|
15523
|
-
long_title="Minimize agents and restore them later from a tray"
|
|
15524
|
-
)
|
|
15509
|
+
# The user expanded the same feature; the first title remains "Minimize Agents":
|
|
15510
|
+
update_terminal_activity(activity="Adding restore from the tray")
|
|
15525
15511
|
\`\`\`
|
|
15526
15512
|
|
|
15527
15513
|
### \u2705 RADICAL TOPIC CHANGE \u2192 set a NEW general title (mandatory):
|
|
@@ -15530,7 +15516,8 @@ set_terminal_title(
|
|
|
15530
15516
|
User: "leave that, now let's prepare the release notes"
|
|
15531
15517
|
set_terminal_title(
|
|
15532
15518
|
title="Release Notes",
|
|
15533
|
-
long_title="Preparing the release notes for the next version"
|
|
15519
|
+
long_title="Preparing the release notes for the next version",
|
|
15520
|
+
replace_existing=true
|
|
15534
15521
|
)
|
|
15535
15522
|
update_terminal_activity(activity="Drafting the release notes")
|
|
15536
15523
|
# \u274C WRONG: calling only update_terminal_activity here \u2014 the tab would still
|
|
@@ -15539,9 +15526,8 @@ update_terminal_activity(activity="Drafting the release notes")
|
|
|
15539
15526
|
|
|
15540
15527
|
## \u26A0\uFE0F WHEN TO USE WHICH
|
|
15541
15528
|
|
|
15542
|
-
- **General title (set_terminal_title):** once
|
|
15543
|
-
|
|
15544
|
-
session \u2014 but NEVER leave a stale title on an agent that moved to another topic.
|
|
15529
|
+
- **General title (set_terminal_title):** once per conversation from the first request.
|
|
15530
|
+
Replace only after a radical functionality pivot, with \`replace_existing=true\`.
|
|
15545
15531
|
- **Current activity (update_terminal_activity):** every time you move to a new product
|
|
15546
15532
|
step. Call it freely - it never disturbs the tab.
|
|
15547
15533
|
|
|
@@ -15617,14 +15603,14 @@ update_terminal_activity(activity="Investigating the output handler cost") \u
|
|
|
15617
15603
|
**Bad 3 - Never setting a general title:**
|
|
15618
15604
|
\`\`\`
|
|
15619
15605
|
# Only calling update_terminal_activity, so the tab never gets a product label.
|
|
15620
|
-
\u2705
|
|
15606
|
+
\u2705 Set the title ONCE from the first user request so the tab is meaningful.
|
|
15621
15607
|
\`\`\`
|
|
15622
15608
|
|
|
15623
15609
|
**Bad 4 - Radical topic change but the title never changes:**
|
|
15624
15610
|
\`\`\`
|
|
15625
15611
|
# Title: "Promo Video". The user then says: "now let's debug the login crash"
|
|
15626
15612
|
update_terminal_activity(activity="Debugging the login crash") \u2190 \u274C tab still says "Promo Video"
|
|
15627
|
-
\u2705 set_terminal_title(title="Login Crash", long_title="Debugging the crash when logging in")
|
|
15613
|
+
\u2705 set_terminal_title(title="Login Crash", long_title="Debugging the crash when logging in", replace_existing=true)
|
|
15628
15614
|
\u2705 update_terminal_activity(activity="Reproducing the login crash")
|
|
15629
15615
|
\`\`\`
|
|
15630
15616
|
|
|
@@ -15639,26 +15625,25 @@ set_terminal_title(title="Settings E2E Tests") \u2190 \u274C testing is a STEP
|
|
|
15639
15625
|
|
|
15640
15626
|
## \u{1F6A8} FINAL REMINDER
|
|
15641
15627
|
|
|
15642
|
-
- Set the **general title AND
|
|
15643
|
-
|
|
15644
|
-
radically \u2014 never leave a stale title.
|
|
15628
|
+
- Set the **general title AND GOAL once per conversation**, from the first user request.
|
|
15629
|
+
Follow-ups never retitle; a radical functionality pivot uses \`replace_existing=true\`.
|
|
15645
15630
|
- Keep the **current activity** flowing with \`update_terminal_activity\` (product-level),
|
|
15646
15631
|
one short sentence per step.
|
|
15647
15632
|
- The tab should stay stable; the hover + clock-button log carry the detail.
|
|
15648
15633
|
- Do NOT create or manage tasks \u2014 automatic task management is disabled.
|
|
15649
15634
|
|
|
15650
15635
|
**MEMORIZE:**
|
|
15651
|
-
1. **
|
|
15636
|
+
1. **First request \u2192 \`set_terminal_title(title, long_title)\` once**
|
|
15652
15637
|
2. **New step \u2192 \`update_terminal_activity\` (product step)**
|
|
15653
|
-
3. **
|
|
15638
|
+
3. **Radical functionality pivot \u2192 \`set_terminal_title(..., replace_existing=true)\`**
|
|
15654
15639
|
4. **\u{1F3C1} Finishing \u2192 final \`update_terminal_activity\` summary**
|
|
15655
15640
|
|
|
15656
15641
|
## Quick Decision Guide
|
|
15657
15642
|
|
|
15658
15643
|
**Agent Title?**
|
|
15659
|
-
-
|
|
15660
|
-
-
|
|
15661
|
-
- Radical
|
|
15644
|
+
- Set it from the first user request, once per conversation
|
|
15645
|
+
- Follow-up work changes activity, never the title
|
|
15646
|
+
- Radical functionality pivot \u2192 replace with \`replace_existing=true\`
|
|
15662
15647
|
|
|
15663
15648
|
**Tasks?**
|
|
15664
15649
|
- Automatic task management is DISABLED \u2014 never create or manage tasks
|
|
@@ -18879,6 +18864,7 @@ var require_provider_auth = __commonJS({
|
|
|
18879
18864
|
/\bunauthenticated\b/i,
|
|
18880
18865
|
/\bauthentication required\b/i,
|
|
18881
18866
|
/\bplease (?:run|use) [^\n]*(?:login|log in|sign in)\b/i,
|
|
18867
|
+
/\brun [^\n]*(?:login|log in|sign in)\b/i,
|
|
18882
18868
|
/\b(?:login|log in|sign in) (?:is )?required\b/i,
|
|
18883
18869
|
/\bmissing (?:an? )?(?:api key|access token|auth token|credentials?)\b/i,
|
|
18884
18870
|
/\b(?:invalid|expired) (?:api key|access token|auth token|credentials?)\b/i,
|
|
@@ -19240,7 +19226,6 @@ var require_codex_app_server_driver = __commonJS({
|
|
|
19240
19226
|
var DEFAULT_SERVICE_TIER_ID = "default";
|
|
19241
19227
|
var EPHEMERAL_CODEX_HOME_PREFIX = "codeagentswarm-codex-home-";
|
|
19242
19228
|
var EPHEMERAL_CODEX_HOME_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
19243
|
-
var REQUIRED_TASK_MCP_TOOL = "check_active";
|
|
19244
19229
|
var TEXT_ONLY_INSTRUCTIONS = "Answer with plain text only. Do not call tools, commands, apps, skills, web search, MCP servers, or subagents.";
|
|
19245
19230
|
var IMAGE_ONLY_INSTRUCTIONS = "Generate exactly one image with the built-in image generation capability. Do not call commands, apps, skills, web search, MCP servers, subagents, or any other tool. Do not return prose.";
|
|
19246
19231
|
var TEXT_ONLY_CONFIG_OVERRIDES = Object.freeze([
|
|
@@ -19397,10 +19382,6 @@ var require_codex_app_server_driver = __commonJS({
|
|
|
19397
19382
|
* @param {{name: string, title: string, version: string}} [options.clientInfo]
|
|
19398
19383
|
* @param {number} [options.requestTimeoutMs=30000] Per-request timeout.
|
|
19399
19384
|
* @param {Function} [options.spawnFn] Injectable spawn, for tests.
|
|
19400
|
-
* @param {string} [options.requiredMcpServer] MCP server whose activation
|
|
19401
|
-
* check is repaired before the first turn when possible.
|
|
19402
|
-
* @param {Function} [options.repairMcpConfig] Repairs the on-disk MCP config
|
|
19403
|
-
* before the running app-server reloads it.
|
|
19404
19385
|
* @param {{register: Function, unregister: Function}} [options.processRegistry]
|
|
19405
19386
|
* PID registry the child is tracked in; injectable for tests.
|
|
19406
19387
|
*/
|
|
@@ -19410,9 +19391,7 @@ var require_codex_app_server_driver = __commonJS({
|
|
|
19410
19391
|
clientInfo,
|
|
19411
19392
|
requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS,
|
|
19412
19393
|
spawnFn,
|
|
19413
|
-
processRegistry
|
|
19414
|
-
requiredMcpServer,
|
|
19415
|
-
repairMcpConfig
|
|
19394
|
+
processRegistry
|
|
19416
19395
|
} = {}) {
|
|
19417
19396
|
super();
|
|
19418
19397
|
this._binaryPath = binaryPath;
|
|
@@ -19421,8 +19400,6 @@ var require_codex_app_server_driver = __commonJS({
|
|
|
19421
19400
|
this._requestTimeoutMs = requestTimeoutMs;
|
|
19422
19401
|
this._spawnFn = spawnFn || spawn;
|
|
19423
19402
|
this._processRegistry = processRegistry || require_spawned_process_registry();
|
|
19424
|
-
this._requiredMcpServer = requiredMcpServer || null;
|
|
19425
|
-
this._repairMcpConfig = repairMcpConfig || null;
|
|
19426
19403
|
this._child = null;
|
|
19427
19404
|
this._pendingRequests = /* @__PURE__ */ new Map();
|
|
19428
19405
|
this._pendingApprovals = /* @__PURE__ */ new Map();
|
|
@@ -19969,7 +19946,7 @@ var require_codex_app_server_driver = __commonJS({
|
|
|
19969
19946
|
initialTurnsPage: {
|
|
19970
19947
|
limit: INITIAL_HISTORY_TURN_PAGE_SIZE,
|
|
19971
19948
|
sortDirection: "desc",
|
|
19972
|
-
itemsView: "
|
|
19949
|
+
itemsView: "full"
|
|
19973
19950
|
},
|
|
19974
19951
|
...threadParams
|
|
19975
19952
|
});
|
|
@@ -19995,13 +19972,6 @@ var require_codex_app_server_driver = __commonJS({
|
|
|
19995
19972
|
}
|
|
19996
19973
|
}
|
|
19997
19974
|
this._threadId = ((_a = result == null ? void 0 : result.thread) == null ? void 0 : _a.id) || (result == null ? void 0 : result.threadId) || (resumeSessionId || null);
|
|
19998
|
-
if (!toolsDisabled && !imageGenerationOnly) {
|
|
19999
|
-
try {
|
|
20000
|
-
await this._ensureRequiredMcpServer(this._threadId);
|
|
20001
|
-
} catch (error) {
|
|
20002
|
-
console.warn(`[CodexAppServerDriver] Continuing without verified task MCP tools: ${error.message}`);
|
|
20003
|
-
}
|
|
20004
|
-
}
|
|
20005
19975
|
this._sessionCwd = (result == null ? void 0 : result.cwd) || ((_b = result == null ? void 0 : result.thread) == null ? void 0 : _b.cwd) || cwd;
|
|
20006
19976
|
let historyPage = result == null ? void 0 : result.initialTurnsPage;
|
|
20007
19977
|
const returnedTurns = Array.isArray((_c = result == null ? void 0 : result.thread) == null ? void 0 : _c.turns) ? result.thread.turns : [];
|
|
@@ -20011,7 +19981,7 @@ var require_codex_app_server_driver = __commonJS({
|
|
|
20011
19981
|
threadId: this._threadId,
|
|
20012
19982
|
limit: INITIAL_HISTORY_TURN_PAGE_SIZE,
|
|
20013
19983
|
sortDirection: "desc",
|
|
20014
|
-
itemsView: "
|
|
19984
|
+
itemsView: "full"
|
|
20015
19985
|
});
|
|
20016
19986
|
} catch (_) {
|
|
20017
19987
|
}
|
|
@@ -20060,15 +20030,6 @@ var require_codex_app_server_driver = __commonJS({
|
|
|
20060
20030
|
} while (cursor);
|
|
20061
20031
|
return servers;
|
|
20062
20032
|
}
|
|
20063
|
-
async _ensureRequiredMcpServer(threadId) {
|
|
20064
|
-
if (!this._requiredMcpServer) return;
|
|
20065
|
-
const connected = (servers) => servers.some((server) => (server == null ? void 0 : server.name) === this._requiredMcpServer && Object.values(server.tools || {}).some((tool) => (tool == null ? void 0 : tool.name) === REQUIRED_TASK_MCP_TOOL));
|
|
20066
|
-
if (connected(await this._listMcpServers(threadId))) return;
|
|
20067
|
-
if (this._repairMcpConfig && await this._repairMcpConfig() === false) {
|
|
20068
|
-
throw new Error("CodeAgentSwarm could not repair the Codex MCP configuration. Restart CodeAgentSwarm and retry Chat.");
|
|
20069
|
-
}
|
|
20070
|
-
await this._request("config/mcpServer/reload", null);
|
|
20071
|
-
}
|
|
20072
20033
|
/**
|
|
20073
20034
|
* Build a resumed thread's past items as historical `item.completed` events.
|
|
20074
20035
|
*
|
|
@@ -30461,6 +30422,18 @@ var require_mcp_stdio_server = __commonJS({
|
|
|
30461
30422
|
} catch (e) {
|
|
30462
30423
|
}
|
|
30463
30424
|
}
|
|
30425
|
+
_hasNudgeMarker(kind) {
|
|
30426
|
+
try {
|
|
30427
|
+
const os2 = require("os");
|
|
30428
|
+
const fs2 = require("fs");
|
|
30429
|
+
const stateDir = path.join(os2.homedir(), ".codeagentswarm", "terminal-nudge-state");
|
|
30430
|
+
const rawKey = process.env.CODEAGENTSWARM_TERMINAL_ID || process.env.CODEAGENTSWARM_CURRENT_QUADRANT;
|
|
30431
|
+
const key = String(rawKey || "").replace(/[^A-Za-z0-9_-]/g, "_");
|
|
30432
|
+
return !!key && fs2.existsSync(path.join(stateDir, `${key}.${kind}`));
|
|
30433
|
+
} catch (e) {
|
|
30434
|
+
return false;
|
|
30435
|
+
}
|
|
30436
|
+
}
|
|
30464
30437
|
// Resolve the current terminal id (1-based) from the environment.
|
|
30465
30438
|
_getCurrentTerminalId() {
|
|
30466
30439
|
const terminalId = process.env.CODEAGENTSWARM_CURRENT_QUADRANT;
|
|
@@ -30479,20 +30452,30 @@ var require_mcp_stdio_server = __commonJS({
|
|
|
30479
30452
|
}
|
|
30480
30453
|
// Set the GENERAL terminal title: the sticky tab label that represents the
|
|
30481
30454
|
// product-level goal of what this terminal is working on. Set it ONCE at the
|
|
30482
|
-
// start of
|
|
30483
|
-
//
|
|
30484
|
-
//
|
|
30485
|
-
// for that.
|
|
30455
|
+
// start of the conversation. Later calls preserve it unless the caller explicitly
|
|
30456
|
+
// declares a radical topic change. It does NOT represent the current step — use
|
|
30457
|
+
// update_terminal_activity for that.
|
|
30486
30458
|
async setTerminalTitle(params) {
|
|
30487
|
-
const { title, long_title } = params;
|
|
30459
|
+
const { title, long_title, replace_existing } = params;
|
|
30488
30460
|
if (!title) {
|
|
30489
30461
|
throw new Error("title is required");
|
|
30490
30462
|
}
|
|
30491
30463
|
if (isPlaceholderTitle(title)) {
|
|
30492
30464
|
throw new Error(`"${title}" looks like example text copied from the tool documentation, not a real title. Call the tool again with a title that describes the ACTUAL feature or goal you are working on in this agent (max 6 words).`);
|
|
30493
30465
|
}
|
|
30494
|
-
|
|
30466
|
+
if (replace_existing !== void 0 && typeof replace_existing !== "boolean") {
|
|
30467
|
+
throw new Error("replace_existing must be a boolean");
|
|
30468
|
+
}
|
|
30495
30469
|
const terminalId = this._getCurrentTerminalId();
|
|
30470
|
+
if (replace_existing !== true && this._hasNudgeMarker("title")) {
|
|
30471
|
+
return {
|
|
30472
|
+
terminal_id: terminalId,
|
|
30473
|
+
updated: false,
|
|
30474
|
+
preserved: true,
|
|
30475
|
+
message: "The existing conversation title was preserved. Use update_terminal_activity for follow-up work; set replace_existing=true only after the user pivots to a completely different functionality."
|
|
30476
|
+
};
|
|
30477
|
+
}
|
|
30478
|
+
const shortTitle = this.generateShortTitle(title);
|
|
30496
30479
|
const currentTask = this._getCurrentTask(terminalId);
|
|
30497
30480
|
const taskId = currentTask ? currentTask.id : null;
|
|
30498
30481
|
let longTitle = long_title;
|
|
@@ -31390,7 +31373,7 @@ Use 'clear' to remove the status.`;
|
|
|
31390
31373
|
},
|
|
31391
31374
|
{
|
|
31392
31375
|
name: "set_terminal_title",
|
|
31393
|
-
description:
|
|
31376
|
+
description: "Set the GENERAL agent title AND the agent GOAL from the first user request that established this conversation's topic. Pass BOTH text arguments because the user sees them together. This is once per conversation, NOT once per user message, turn, task, review, validation, or resumed session. Follow-up work belongs in update_terminal_activity and repeated calls preserve the original title. Only a user pivot to a completely different functionality may replace it, by passing replace_existing=true. LANGUAGE: write both text fields in the SAME language the user is speaking.",
|
|
31394
31377
|
inputSchema: {
|
|
31395
31378
|
type: "object",
|
|
31396
31379
|
properties: {
|
|
@@ -31401,6 +31384,10 @@ Use 'clear' to remove the status.`;
|
|
|
31401
31384
|
long_title: {
|
|
31402
31385
|
type: "string",
|
|
31403
31386
|
description: `The agent GOAL: one sentence saying what this agent is FOR \u2014 the outcome the work is aiming at, not the current step. ALWAYS provide it: the user reads it in the Agent hover, labelled GOAL, under the short title. Write the real goal in the user's language. Do NOT restate the title or prefix it with "Working on:".`
|
|
31387
|
+
},
|
|
31388
|
+
replace_existing: {
|
|
31389
|
+
type: "boolean",
|
|
31390
|
+
description: "Leave false or omit for normal follow-up work. Set true ONLY when the user explicitly pivots this existing conversation to a completely different functionality; reviews, tests, fixes, implementation phases, and refinements of the original request are activities and must not replace the title."
|
|
31404
31391
|
}
|
|
31405
31392
|
},
|
|
31406
31393
|
// long_title is NOT in `required` on purpose: some agent clients
|
|
@@ -31854,7 +31841,8 @@ Use 'clear' to remove the status.`;
|
|
|
31854
31841
|
case "set_terminal_title":
|
|
31855
31842
|
result = await this.setTerminalTitle({
|
|
31856
31843
|
title: args.title,
|
|
31857
|
-
long_title: args.long_title
|
|
31844
|
+
long_title: args.long_title,
|
|
31845
|
+
replace_existing: args.replace_existing
|
|
31858
31846
|
});
|
|
31859
31847
|
break;
|
|
31860
31848
|
case "update_terminal_activity":
|
|
@@ -33683,18 +33671,13 @@ var require_driver_chat_manager = __commonJS({
|
|
|
33683
33671
|
});
|
|
33684
33672
|
});
|
|
33685
33673
|
}
|
|
33686
|
-
function defaultCreateDriver({ agent, env, binaryPath
|
|
33674
|
+
function defaultCreateDriver({ agent, env, binaryPath }) {
|
|
33687
33675
|
if (agent === "claude") return new ClaudeAgentSdkDriver({ env, binaryPath });
|
|
33688
33676
|
if (agent === "antigravity") return new AntigravityPrintDriver({ env, binaryPath });
|
|
33689
33677
|
if (agent === "opencode" || agent === "kimi" || agent === "grok" || agent === "cursor") {
|
|
33690
33678
|
return new AcpAgentDriver({ provider: agent, env, binaryPath });
|
|
33691
33679
|
}
|
|
33692
|
-
return new CodexAppServerDriver({
|
|
33693
|
-
env,
|
|
33694
|
-
binaryPath,
|
|
33695
|
-
requiredMcpServer,
|
|
33696
|
-
repairMcpConfig
|
|
33697
|
-
});
|
|
33680
|
+
return new CodexAppServerDriver({ env, binaryPath });
|
|
33698
33681
|
}
|
|
33699
33682
|
var DriverChatManager = class extends EventEmitter {
|
|
33700
33683
|
/**
|
|
@@ -33961,6 +33944,7 @@ var require_driver_chat_manager = __commonJS({
|
|
|
33961
33944
|
// main-process placeholder, so return that same UUID for persistence
|
|
33962
33945
|
// and instance-safe MCP notification routing.
|
|
33963
33946
|
terminalUuid: env.CODEAGENTSWARM_TERMINAL_ID || null,
|
|
33947
|
+
communicationEnabled: env.CODEAGENTSWARM_SESSION_COMMUNICATION_ENABLED === "1",
|
|
33964
33948
|
model: session.model,
|
|
33965
33949
|
effort: session.effort || resolvedEffort,
|
|
33966
33950
|
serviceTier: session.serviceTier ?? (rejected.has("serviceTier") ? null : (_a = selections.find((selection) => (selection == null ? void 0 : selection.id) === "serviceTier")) == null ? void 0 : _a.value) ?? null,
|
|
@@ -34722,11 +34706,13 @@ var require_chat_history_pagination = __commonJS({
|
|
|
34722
34706
|
return Date.parse(value);
|
|
34723
34707
|
}
|
|
34724
34708
|
function normalizeConversationMessages(messages) {
|
|
34709
|
+
let internalTurn = false;
|
|
34725
34710
|
return (Array.isArray(messages) ? messages : []).flatMap((message) => {
|
|
34726
34711
|
const role = (message == null ? void 0 : message.role) === "assistant" ? "assistant_message" : (message == null ? void 0 : message.role) === "user" ? "user_message" : null;
|
|
34727
34712
|
const text = [message == null ? void 0 : message.content, message == null ? void 0 : message.text, message == null ? void 0 : message.displayText].find((value) => typeof value === "string" && value.trim());
|
|
34728
34713
|
const attachments = Array.isArray(message == null ? void 0 : message.attachments) ? message.attachments : [];
|
|
34729
|
-
|
|
34714
|
+
if (role === "user_message") internalTurn = Boolean(text && parseSessionCoordinationPrompt(text));
|
|
34715
|
+
return role && (text || attachments.length) && !internalTurn ? [{ role, text: text || "", attachments, timestamp: message.timestamp }] : [];
|
|
34730
34716
|
});
|
|
34731
34717
|
}
|
|
34732
34718
|
function boundedConversationMessages(messages, { limit = 30, maxMessageChars = 8e3, maxBytes = 22e4 } = {}) {
|
|
@@ -34777,12 +34763,14 @@ var require_chat_history_pagination = __commonJS({
|
|
|
34777
34763
|
before,
|
|
34778
34764
|
anchor,
|
|
34779
34765
|
knownCount = 0,
|
|
34766
|
+
hydratedCount = 0,
|
|
34780
34767
|
limit = DEFAULT_HISTORY_PAGE_SIZE
|
|
34781
34768
|
} = {}) {
|
|
34782
34769
|
const normalized = normalizeConversationMessages(messages);
|
|
34783
34770
|
const safeLimit = Number.isSafeInteger(limit) && limit > 0 ? limit : DEFAULT_HISTORY_PAGE_SIZE;
|
|
34784
34771
|
const anchorIndex = findConversationAnchor(normalized, anchor);
|
|
34785
|
-
const
|
|
34772
|
+
const hydratedEnd = Math.max(0, normalized.length - Math.max(0, Number(hydratedCount) || 0));
|
|
34773
|
+
const end = Number.isSafeInteger(before) ? Math.max(0, Math.min(before, normalized.length)) : Math.min(hydratedEnd, anchorIndex ?? Math.max(0, normalized.length - Math.max(0, Number(knownCount) || 0)));
|
|
34786
34774
|
const start = Math.max(0, end - safeLimit);
|
|
34787
34775
|
return {
|
|
34788
34776
|
messages: normalized.slice(start, end).map((message, offset) => ({
|
|
@@ -35048,6 +35036,7 @@ var require_mobile_runtime = __commonJS({
|
|
|
35048
35036
|
var { parseSessionCoordinationPrompt } = require_session_coordination_message();
|
|
35049
35037
|
var {
|
|
35050
35038
|
conversationMessagesToEvents,
|
|
35039
|
+
normalizeConversationMessages,
|
|
35051
35040
|
pageConversationMessages
|
|
35052
35041
|
} = require_chat_history_pagination();
|
|
35053
35042
|
var PROTOCOL_VERSION = 2;
|
|
@@ -35353,6 +35342,7 @@ var require_mobile_runtime = __commonJS({
|
|
|
35353
35342
|
listProjectDirectories = null,
|
|
35354
35343
|
createProject = null,
|
|
35355
35344
|
updateProject = null,
|
|
35345
|
+
gitAvailability = null,
|
|
35356
35346
|
projectIconAvailability = null,
|
|
35357
35347
|
generateProjectIcon = null,
|
|
35358
35348
|
registerProject = null,
|
|
@@ -35423,6 +35413,7 @@ var require_mobile_runtime = __commonJS({
|
|
|
35423
35413
|
this.listProjectDirectories = listProjectDirectories;
|
|
35424
35414
|
this.createProject = createProject;
|
|
35425
35415
|
this.updateProject = updateProject;
|
|
35416
|
+
this.gitAvailability = gitAvailability;
|
|
35426
35417
|
this.projectIconAvailability = projectIconAvailability;
|
|
35427
35418
|
this.generateProjectIcon = generateProjectIcon;
|
|
35428
35419
|
this.registerProject = registerProject;
|
|
@@ -35568,6 +35559,7 @@ var require_mobile_runtime = __commonJS({
|
|
|
35568
35559
|
accountLabel: session.accountLabel,
|
|
35569
35560
|
threadId: session.threadId,
|
|
35570
35561
|
terminalUuid: session.terminalUuid,
|
|
35562
|
+
communicationEnabled: session.communicationEnabled === true,
|
|
35571
35563
|
terminalOrder: session.terminalOrder,
|
|
35572
35564
|
cwd: session.cwd,
|
|
35573
35565
|
model: session.model,
|
|
@@ -35875,13 +35867,16 @@ var require_mobile_runtime = __commonJS({
|
|
|
35875
35867
|
});
|
|
35876
35868
|
}
|
|
35877
35869
|
publishProjectIconEvent(event = {}) {
|
|
35870
|
+
const iconDataUrl = typeof event.iconDataUrl === "string" && event.iconDataUrl.length <= 1e5 ? event.iconDataUrl : null;
|
|
35878
35871
|
return this._publish("project.icon.generated", {
|
|
35879
35872
|
jobId: cleanText(event.jobId, 100),
|
|
35880
35873
|
projectId: cleanText(event.projectId, 128),
|
|
35881
35874
|
success: event.success === true,
|
|
35882
35875
|
applied: event.applied === true,
|
|
35883
35876
|
unavailable: event.unavailable === true,
|
|
35884
|
-
...cleanText(event.error, 500) ? { error: cleanText(event.error, 500) } : {}
|
|
35877
|
+
...cleanText(event.error, 500) ? { error: cleanText(event.error, 500) } : {},
|
|
35878
|
+
...cleanText(event.icon, 300) ? { icon: cleanText(event.icon, 300) } : {},
|
|
35879
|
+
...iconDataUrl ? { iconDataUrl } : {}
|
|
35885
35880
|
});
|
|
35886
35881
|
}
|
|
35887
35882
|
publishProviderLoginEvent(event = {}) {
|
|
@@ -35939,6 +35934,7 @@ var require_mobile_runtime = __commonJS({
|
|
|
35939
35934
|
accountLabel: started.accountLabel || null,
|
|
35940
35935
|
threadId: started.threadId,
|
|
35941
35936
|
terminalUuid: started.terminalUuid,
|
|
35937
|
+
communicationEnabled: started.communicationEnabled === true,
|
|
35942
35938
|
terminalOrder: Number.isSafeInteger(started.terminalId) && started.terminalId > 0 ? started.terminalId : null,
|
|
35943
35939
|
desktopTerminalId: Number.isSafeInteger(started.terminalId) && started.terminalId > 0 ? started.terminalId : null,
|
|
35944
35940
|
cwd: started.cwd,
|
|
@@ -35964,6 +35960,7 @@ var require_mobile_runtime = __commonJS({
|
|
|
35964
35960
|
accountLabel: started.accountLabel || null,
|
|
35965
35961
|
threadId: started.threadId,
|
|
35966
35962
|
terminalUuid: started.terminalUuid,
|
|
35963
|
+
communicationEnabled: started.communicationEnabled === true,
|
|
35967
35964
|
terminalOrder: Number.isSafeInteger(started.terminalId) && started.terminalId > 0 ? started.terminalId : null,
|
|
35968
35965
|
cwd: started.cwd,
|
|
35969
35966
|
model: started.model,
|
|
@@ -36019,11 +36016,11 @@ var require_mobile_runtime = __commonJS({
|
|
|
36019
36016
|
return;
|
|
36020
36017
|
}
|
|
36021
36018
|
if (!Array.isArray(messages) || !messages.length) return;
|
|
36022
|
-
const recent = messages.slice(-200);
|
|
36019
|
+
const recent = normalizeConversationMessages(messages).slice(-200);
|
|
36023
36020
|
recent.forEach((message, index) => {
|
|
36024
36021
|
var _a2, _b2;
|
|
36025
|
-
const role =
|
|
36026
|
-
const text = cleanText(
|
|
36022
|
+
const role = message.role;
|
|
36023
|
+
const text = cleanText(message.text, MAX_INITIAL_PROMPT_CHARS);
|
|
36027
36024
|
const attachments = Array.isArray(message == null ? void 0 : message.attachments) ? message.attachments : [];
|
|
36028
36025
|
if (!role || !text && !attachments.length) return;
|
|
36029
36026
|
const key = `${role}\0${text}`;
|
|
@@ -36315,6 +36312,7 @@ var require_mobile_runtime = __commonJS({
|
|
|
36315
36312
|
accountLabel: null,
|
|
36316
36313
|
threadId: null,
|
|
36317
36314
|
terminalUuid: null,
|
|
36315
|
+
communicationEnabled: false,
|
|
36318
36316
|
terminalOrder: null,
|
|
36319
36317
|
desktopTerminalId: null,
|
|
36320
36318
|
cwd: null,
|
|
@@ -36579,7 +36577,7 @@ var require_mobile_runtime = __commonJS({
|
|
|
36579
36577
|
}
|
|
36580
36578
|
}
|
|
36581
36579
|
async _executeCommand(command = {}, context = {}) {
|
|
36582
|
-
var _a, _b, _c, _d, _e, _f;
|
|
36580
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
36583
36581
|
this._pruneAttachmentUploads();
|
|
36584
36582
|
const sessionId = command.sessionId;
|
|
36585
36583
|
const payload = command.payload || {};
|
|
@@ -36689,10 +36687,15 @@ var require_mobile_runtime = __commonJS({
|
|
|
36689
36687
|
this.publishProjects();
|
|
36690
36688
|
return result;
|
|
36691
36689
|
}
|
|
36690
|
+
if (command.type === "project.git.availability") {
|
|
36691
|
+
if (typeof this.gitAvailability !== "function") return { available: false };
|
|
36692
|
+
exactPayload(["rootId"]);
|
|
36693
|
+
return this.gitAvailability({ rootId: cleanText(payload.rootId, 128) });
|
|
36694
|
+
}
|
|
36692
36695
|
if (command.type === "project.icon.availability") {
|
|
36693
36696
|
if (typeof this.projectIconAvailability !== "function") return { available: false };
|
|
36694
|
-
exactPayload([]);
|
|
36695
|
-
return this.projectIconAvailability();
|
|
36697
|
+
exactPayload(["projectId"]);
|
|
36698
|
+
return this.projectIconAvailability({ projectId: cleanText(payload.projectId, 128) });
|
|
36696
36699
|
}
|
|
36697
36700
|
if (command.type === "project.icon.generate") {
|
|
36698
36701
|
if (typeof this.generateProjectIcon !== "function") throw new Error("Codex icon generation is unavailable");
|
|
@@ -36706,13 +36709,23 @@ var require_mobile_runtime = __commonJS({
|
|
|
36706
36709
|
if (command.type === "project.register") {
|
|
36707
36710
|
if (typeof this.registerProject !== "function") throw new Error("Remote project registration is unavailable");
|
|
36708
36711
|
exactPayload(["rootId", "relativePath", "requestId"]);
|
|
36709
|
-
|
|
36712
|
+
const result = await this.registerProject({ rootId: payload.rootId, relativePath: payload.relativePath, requestId: mutationRequestId() });
|
|
36713
|
+
this.publishProjects();
|
|
36714
|
+
return result;
|
|
36710
36715
|
}
|
|
36711
36716
|
if (command.type === "project.clone") {
|
|
36712
36717
|
if (typeof this.cloneProject !== "function") throw new Error("Remote project cloning is unavailable");
|
|
36713
|
-
exactPayload(["rootId", "url", "relativePath", "requestId"]);
|
|
36718
|
+
exactPayload(["rootId", "url", "relativePath", "displayName", "color", "icon", "requestId"]);
|
|
36714
36719
|
if (typeof payload.requestId !== "string" || !payload.requestId) throw new Error("A clone requestId is required");
|
|
36715
|
-
return this.cloneProject({
|
|
36720
|
+
return this.cloneProject({
|
|
36721
|
+
rootId: payload.rootId,
|
|
36722
|
+
url: payload.url,
|
|
36723
|
+
relativePath: payload.relativePath,
|
|
36724
|
+
displayName: payload.displayName,
|
|
36725
|
+
color: payload.color,
|
|
36726
|
+
icon: payload.icon,
|
|
36727
|
+
requestId: payload.requestId
|
|
36728
|
+
});
|
|
36716
36729
|
}
|
|
36717
36730
|
if (command.type === "project.clone.cancel") {
|
|
36718
36731
|
if (typeof this.cancelProjectClone !== "function") throw new Error("Remote clone cancellation is unavailable");
|
|
@@ -36984,6 +36997,7 @@ var require_mobile_runtime = __commonJS({
|
|
|
36984
36997
|
agent: session.agent
|
|
36985
36998
|
});
|
|
36986
36999
|
const knownCount = Array.from(session.items.values()).filter(isConversationItem).length;
|
|
37000
|
+
const hydratedCount = ((_d = (_c = context.client) == null ? void 0 : _c.subscriptions) == null ? void 0 : _d.has(sessionId)) ? this._subscriptionSnapshot(session).items.filter(isConversationItem).length : 0;
|
|
36987
37001
|
const page = pageConversationMessages(messages, {
|
|
36988
37002
|
before: Number.isSafeInteger(payload.before) ? payload.before : void 0,
|
|
36989
37003
|
anchor: payload.anchor && typeof payload.anchor === "object" ? {
|
|
@@ -36992,6 +37006,7 @@ var require_mobile_runtime = __commonJS({
|
|
|
36992
37006
|
timestamp: cleanText(payload.anchor.timestamp, 64)
|
|
36993
37007
|
} : null,
|
|
36994
37008
|
knownCount: Number.isSafeInteger(payload.knownCount) ? payload.knownCount : knownCount,
|
|
37009
|
+
hydratedCount,
|
|
36995
37010
|
limit: 30
|
|
36996
37011
|
});
|
|
36997
37012
|
const events = conversationMessagesToEvents(page.messages, {
|
|
@@ -37063,7 +37078,7 @@ var require_mobile_runtime = __commonJS({
|
|
|
37063
37078
|
const value = typeof payload.value === "boolean" && REASONING_CONFIG_IDS.has(configId) ? payload.value : cleanText(payload.value, 200);
|
|
37064
37079
|
if (value === null || value === "") throw new Error("Choose a configuration value");
|
|
37065
37080
|
const session = this._session(sessionId);
|
|
37066
|
-
if (((
|
|
37081
|
+
if (((_e = session.currentTurn) == null ? void 0 : _e.state) === "running") {
|
|
37067
37082
|
throw new Error("Wait for the current response to finish");
|
|
37068
37083
|
}
|
|
37069
37084
|
return this.manager.setConfigOption(sessionId, configId, value);
|
|
@@ -37209,11 +37224,11 @@ var require_mobile_runtime = __commonJS({
|
|
|
37209
37224
|
for (const uploadId of uploadIds) this.attachmentUploads.delete(uploadId);
|
|
37210
37225
|
return { accepted: true, ...(delivered == null ? void 0 : delivered.turnId) ? { turnId: delivered.turnId } : {} };
|
|
37211
37226
|
} catch (error) {
|
|
37212
|
-
const localEcho = (
|
|
37227
|
+
const localEcho = (_f = this.sessions.get(sessionId)) == null ? void 0 : _f.items.get(localEchoId);
|
|
37213
37228
|
if (localEcho == null ? void 0 : localEcho.providerItemId) return { accepted: true };
|
|
37214
37229
|
this._publishProviderEvent(sessionId, {
|
|
37215
37230
|
eventId: crypto.randomUUID(),
|
|
37216
|
-
provider: (
|
|
37231
|
+
provider: (_g = this.sessions.get(sessionId)) == null ? void 0 : _g.provider,
|
|
37217
37232
|
type: "item.completed",
|
|
37218
37233
|
executionOrigin: "main",
|
|
37219
37234
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -37223,7 +37238,7 @@ var require_mobile_runtime = __commonJS({
|
|
|
37223
37238
|
status: "failed",
|
|
37224
37239
|
localEcho: true,
|
|
37225
37240
|
remoteCommand: true,
|
|
37226
|
-
data: { text, attachments: ((
|
|
37241
|
+
data: { text, attachments: ((_h = localEcho == null ? void 0 : localEcho.data) == null ? void 0 : _h.attachments) || [] }
|
|
37227
37242
|
}
|
|
37228
37243
|
});
|
|
37229
37244
|
this.remoteTurnSessions.delete(sessionId);
|
|
@@ -38677,9 +38692,14 @@ var require_remote_runtime_client = __commonJS({
|
|
|
38677
38692
|
"session.resume",
|
|
38678
38693
|
"history.older",
|
|
38679
38694
|
"projects.list",
|
|
38695
|
+
"project.directories.list",
|
|
38696
|
+
"project.update",
|
|
38680
38697
|
"project.register",
|
|
38681
38698
|
"project.clone",
|
|
38682
38699
|
"project.clone.cancel",
|
|
38700
|
+
"project.git.availability",
|
|
38701
|
+
"project.icon.availability",
|
|
38702
|
+
"project.icon.generate",
|
|
38683
38703
|
"project.unregister",
|
|
38684
38704
|
"tasks.list",
|
|
38685
38705
|
"task.create",
|
|
@@ -38708,6 +38728,7 @@ var require_remote_runtime_client = __commonJS({
|
|
|
38708
38728
|
"coordination.transcript",
|
|
38709
38729
|
"coordination.message",
|
|
38710
38730
|
"projects.list",
|
|
38731
|
+
"project.directories.list",
|
|
38711
38732
|
"tasks.list",
|
|
38712
38733
|
"providers.list",
|
|
38713
38734
|
"provider.login.describe",
|
|
@@ -38773,15 +38794,20 @@ var require_remote_runtime_client = __commonJS({
|
|
|
38773
38794
|
assertPublicPayload(child, depth + 1);
|
|
38774
38795
|
}
|
|
38775
38796
|
}
|
|
38776
|
-
function stripPathFields(value, depth = 0) {
|
|
38797
|
+
function stripPathFields(value, depth = 0, preserveRelativePaths = false) {
|
|
38777
38798
|
if (depth > 40) throw new Error("Remote runtime payload is too deeply nested");
|
|
38778
|
-
if (Array.isArray(value)) return value.map((item) => stripPathFields(item, depth + 1));
|
|
38799
|
+
if (Array.isArray(value)) return value.map((item) => stripPathFields(item, depth + 1, preserveRelativePaths));
|
|
38779
38800
|
if (!value || typeof value !== "object") return value;
|
|
38780
38801
|
const clean = {};
|
|
38781
38802
|
for (const [key, child] of Object.entries(value)) {
|
|
38782
38803
|
const normalized = normalizedKey(key);
|
|
38783
|
-
if (PATH_KEYS.has(normalized) || normalized.endsWith("path"))
|
|
38784
|
-
|
|
38804
|
+
if (PATH_KEYS.has(normalized) || normalized.endsWith("path")) {
|
|
38805
|
+
if (preserveRelativePaths && (child === null || isSafeRelativePath(child))) {
|
|
38806
|
+
clean[key] = typeof child === "string" ? child.replace(/\\/g, "/") : null;
|
|
38807
|
+
}
|
|
38808
|
+
continue;
|
|
38809
|
+
}
|
|
38810
|
+
clean[key] = stripPathFields(child, depth + 1, preserveRelativePaths);
|
|
38785
38811
|
}
|
|
38786
38812
|
return clean;
|
|
38787
38813
|
}
|
|
@@ -39326,7 +39352,7 @@ var require_remote_runtime_client = __commonJS({
|
|
|
39326
39352
|
}
|
|
39327
39353
|
if (command.payload !== void 0) {
|
|
39328
39354
|
assertPublicPayload(command.payload);
|
|
39329
|
-
assertPathlessCommand(command.payload, 0, command.type === "project.register" || command.type === "project.clone" || command.type.startsWith("workspace.files."));
|
|
39355
|
+
assertPathlessCommand(command.payload, 0, command.type === "project.directories.list" || command.type === "project.register" || command.type === "project.clone" || command.type.startsWith("workspace.files."));
|
|
39330
39356
|
wire.payload = clone(command.payload);
|
|
39331
39357
|
}
|
|
39332
39358
|
return wire;
|
|
@@ -39453,9 +39479,8 @@ var require_remote_runtime_client = __commonJS({
|
|
|
39453
39479
|
return;
|
|
39454
39480
|
}
|
|
39455
39481
|
if (message.kind === "credential.renewed") {
|
|
39456
|
-
|
|
39457
|
-
|
|
39458
|
-
}
|
|
39482
|
+
const accessExpiresAt = Number(message.accessExpiresAt);
|
|
39483
|
+
if (!this.connection || !Number.isFinite(accessExpiresAt) || Math.abs(accessExpiresAt - this.connection.accessExpiresAt) > 2e3) return;
|
|
39459
39484
|
if (this.renewTimer) clearTimeout(this.renewTimer);
|
|
39460
39485
|
this.renewTimer = null;
|
|
39461
39486
|
this._diagnostic("remote.credential_renewed");
|
|
@@ -39578,7 +39603,7 @@ var require_remote_runtime_client = __commonJS({
|
|
|
39578
39603
|
if (this.runtimeOnline) this._sendRuntimeHello();
|
|
39579
39604
|
}
|
|
39580
39605
|
_handleRuntimeEnvelope(envelope) {
|
|
39581
|
-
var _a, _b;
|
|
39606
|
+
var _a, _b, _c, _d, _e;
|
|
39582
39607
|
let safe;
|
|
39583
39608
|
let bytes;
|
|
39584
39609
|
try {
|
|
@@ -39592,7 +39617,8 @@ var require_remote_runtime_client = __commonJS({
|
|
|
39592
39617
|
throw new Error("Invalid runtime snapshot");
|
|
39593
39618
|
}
|
|
39594
39619
|
}
|
|
39595
|
-
|
|
39620
|
+
const commandType = envelope.kind === "command.result" ? (_c = (_b = (_a = this.pendingCommands.get(envelope.commandId)) == null ? void 0 : _a.message) == null ? void 0 : _b.command) == null ? void 0 : _c.type : null;
|
|
39621
|
+
safe = stripPathFields(envelope, 0, commandType === "project.directories.list");
|
|
39596
39622
|
} catch {
|
|
39597
39623
|
const kind = typeof (envelope == null ? void 0 : envelope.kind) === "string" && /^[a-z][a-z0-9.]{0,63}$/.test(envelope.kind) ? envelope.kind : void 0;
|
|
39598
39624
|
this._diagnostic("remote.runtime_rejected", { reason: "invalid_envelope", kind });
|
|
@@ -39646,8 +39672,8 @@ var require_remote_runtime_client = __commonJS({
|
|
|
39646
39672
|
totalMs: this.connectTrace ? this.now() - this.connectTrace.startedAt : void 0,
|
|
39647
39673
|
reset: safe.reset === true,
|
|
39648
39674
|
bytes,
|
|
39649
|
-
sessions: Array.isArray((
|
|
39650
|
-
projects: Array.isArray((
|
|
39675
|
+
sessions: Array.isArray((_d = safe.snapshot) == null ? void 0 : _d.sessions) ? safe.snapshot.sessions.length : void 0,
|
|
39676
|
+
projects: Array.isArray((_e = safe.snapshot) == null ? void 0 : _e.projects) ? safe.snapshot.projects.length : void 0
|
|
39651
39677
|
});
|
|
39652
39678
|
this.connectTrace = null;
|
|
39653
39679
|
this._emitEnvelope(safe);
|
|
@@ -40235,6 +40261,7 @@ var require_peer_runtime_network = __commonJS({
|
|
|
40235
40261
|
var MAX_PEERS = 32;
|
|
40236
40262
|
var PEER_ACCESS_TTL_MS = 7 * 24 * 60 * 6e4;
|
|
40237
40263
|
var PEER_HANDSHAKE_TIMEOUT_MS = 5e3;
|
|
40264
|
+
var PEER_DENIAL_FEATURE = "peer-denial";
|
|
40238
40265
|
function peerRef(value) {
|
|
40239
40266
|
return value ? crypto.createHash("sha256").update(String(value)).digest("hex").slice(0, 10) : void 0;
|
|
40240
40267
|
}
|
|
@@ -40273,7 +40300,18 @@ var require_peer_runtime_network = __commonJS({
|
|
|
40273
40300
|
return;
|
|
40274
40301
|
}
|
|
40275
40302
|
if (message.kind === "runtime.message" && message.box) {
|
|
40276
|
-
|
|
40303
|
+
let box = message.box;
|
|
40304
|
+
try {
|
|
40305
|
+
const payload = decryptJson(box, this.network.keyPair.secretKey, this.peer.publicKey);
|
|
40306
|
+
if ((payload == null ? void 0 : payload.kind) === "hello" && !(Array.isArray(payload.features) && payload.features.includes(PEER_DENIAL_FEATURE))) {
|
|
40307
|
+
box = encryptJson({
|
|
40308
|
+
...payload,
|
|
40309
|
+
features: [...Array.isArray(payload.features) ? payload.features : [], PEER_DENIAL_FEATURE]
|
|
40310
|
+
}, this.network.keyPair.secretKey, this.peer.publicKey);
|
|
40311
|
+
}
|
|
40312
|
+
} catch {
|
|
40313
|
+
}
|
|
40314
|
+
if (!this.network.relay.sendPeerMessage(this.peer.runtimeId, box, "to-runtime")) {
|
|
40277
40315
|
this.network._diagnostic("peer.route_failed", { peer: peerRef(this.peer.runtimeId), stream: "to-runtime" });
|
|
40278
40316
|
this.offline();
|
|
40279
40317
|
} else if (this.readyState === 1 && !this.handshakeComplete && !this.handshakeTimer) {
|
|
@@ -40283,11 +40321,17 @@ var require_peer_runtime_network = __commonJS({
|
|
|
40283
40321
|
}
|
|
40284
40322
|
receive(box) {
|
|
40285
40323
|
if (this.readyState !== 1) return;
|
|
40324
|
+
let payload;
|
|
40286
40325
|
try {
|
|
40287
|
-
decryptJson(box, this.network.keyPair.secretKey, this.peer.publicKey);
|
|
40326
|
+
payload = decryptJson(box, this.network.keyPair.secretKey, this.peer.publicKey);
|
|
40288
40327
|
this.network.relay.emit("diagnostic", { event: "peer.response_verified", stream: "to-client" });
|
|
40289
40328
|
} catch {
|
|
40290
40329
|
this.network.relay.emit("diagnostic", { event: "peer.response_rejected", reason: "decrypt_failed" });
|
|
40330
|
+
return;
|
|
40331
|
+
}
|
|
40332
|
+
if ((payload == null ? void 0 : payload.kind) === "peer.denied") {
|
|
40333
|
+
this.network._denyPeer(this.peer.runtimeId);
|
|
40334
|
+
return;
|
|
40291
40335
|
}
|
|
40292
40336
|
this.handshakeComplete = true;
|
|
40293
40337
|
if (this.handshakeTimer) clearTimeout(this.handshakeTimer);
|
|
@@ -40327,6 +40371,7 @@ var require_peer_runtime_network = __commonJS({
|
|
|
40327
40371
|
this.saveRosters = saveRosters;
|
|
40328
40372
|
this.rosters = /* @__PURE__ */ new Map();
|
|
40329
40373
|
this.revokedPeers = /* @__PURE__ */ new Set();
|
|
40374
|
+
this.deniedPeers = /* @__PURE__ */ new Set();
|
|
40330
40375
|
this.peers = /* @__PURE__ */ new Map();
|
|
40331
40376
|
this.clients = /* @__PURE__ */ new Map();
|
|
40332
40377
|
this.clientSockets = /* @__PURE__ */ new Map();
|
|
@@ -40374,6 +40419,7 @@ var require_peer_runtime_network = __commonJS({
|
|
|
40374
40419
|
publicKey: peer.publicKey,
|
|
40375
40420
|
name: peer.name.trim().slice(0, 200) || "Connected host"
|
|
40376
40421
|
}])).values()];
|
|
40422
|
+
for (const peer of unique) this.deniedPeers.delete(peer.runtimeId);
|
|
40377
40423
|
if (unique.length) this.rosters.set(deviceId, unique);
|
|
40378
40424
|
else this.rosters.delete(deviceId);
|
|
40379
40425
|
for (const runtimeId of this.revokedPeers) {
|
|
@@ -40428,11 +40474,12 @@ var require_peer_runtime_network = __commonJS({
|
|
|
40428
40474
|
const previous = this.peers.get(runtimeId);
|
|
40429
40475
|
const current = next.get(runtimeId);
|
|
40430
40476
|
if ((current == null ? void 0 : current.publicKey) === previous.publicKey) continue;
|
|
40477
|
+
this.deniedPeers.delete(runtimeId);
|
|
40431
40478
|
this._removePeer(runtimeId);
|
|
40432
40479
|
}
|
|
40433
40480
|
this.peers = next;
|
|
40434
40481
|
for (const peer of this.peers.values()) {
|
|
40435
|
-
if (!this.clients.has(peer.runtimeId)) this._addPeer(peer);
|
|
40482
|
+
if (!this.deniedPeers.has(peer.runtimeId) && !this.clients.has(peer.runtimeId)) this._addPeer(peer);
|
|
40436
40483
|
}
|
|
40437
40484
|
this._notifyClients();
|
|
40438
40485
|
}
|
|
@@ -40517,6 +40564,24 @@ var require_peer_runtime_network = __commonJS({
|
|
|
40517
40564
|
this.serverSockets.delete(runtimeId);
|
|
40518
40565
|
this._diagnostic("peer.removed", { peer: peerRef(runtimeId) });
|
|
40519
40566
|
}
|
|
40567
|
+
_denyPeer(runtimeId) {
|
|
40568
|
+
if (!this.peers.has(runtimeId)) return;
|
|
40569
|
+
this.deniedPeers.add(runtimeId);
|
|
40570
|
+
this._removePeer(runtimeId);
|
|
40571
|
+
this._diagnostic("peer.connection_denied", { peer: peerRef(runtimeId) });
|
|
40572
|
+
this._notifyClients();
|
|
40573
|
+
}
|
|
40574
|
+
_rosterPeer(runtimeId) {
|
|
40575
|
+
let found = null;
|
|
40576
|
+
for (const roster of this.rosters.values()) {
|
|
40577
|
+
for (const peer of roster) {
|
|
40578
|
+
if (peer.runtimeId !== runtimeId) continue;
|
|
40579
|
+
if (found && found.publicKey !== peer.publicKey) return null;
|
|
40580
|
+
found = peer;
|
|
40581
|
+
}
|
|
40582
|
+
}
|
|
40583
|
+
return found;
|
|
40584
|
+
}
|
|
40520
40585
|
_handleRelayEvent(event) {
|
|
40521
40586
|
var _a, _b, _c;
|
|
40522
40587
|
if ((event == null ? void 0 : event.kind) === "peer.online" && ID_PATTERN.test(event.targetRuntimeId || "")) {
|
|
@@ -40537,6 +40602,20 @@ var require_peer_runtime_network = __commonJS({
|
|
|
40537
40602
|
if ((event == null ? void 0 : event.kind) !== "peer.message" || !ID_PATTERN.test(event.sourceRuntimeId || "") || !KEY_PATTERN.test(event.sourcePublicKey || "")) return;
|
|
40538
40603
|
const peer = this.peers.get(event.sourceRuntimeId);
|
|
40539
40604
|
if (!peer || peer.publicKey !== event.sourcePublicKey) {
|
|
40605
|
+
const revokedPeer = this.revokedPeers.has(event.sourceRuntimeId) ? this._rosterPeer(event.sourceRuntimeId) : null;
|
|
40606
|
+
if ((revokedPeer == null ? void 0 : revokedPeer.publicKey) === event.sourcePublicKey && event.stream === "to-runtime") {
|
|
40607
|
+
let payload2;
|
|
40608
|
+
try {
|
|
40609
|
+
payload2 = decryptJson(event.box, this.keyPair.secretKey, revokedPeer.publicKey);
|
|
40610
|
+
} catch {
|
|
40611
|
+
}
|
|
40612
|
+
if ((payload2 == null ? void 0 : payload2.kind) === "hello" && Array.isArray(payload2.features) && payload2.features.includes(PEER_DENIAL_FEATURE)) {
|
|
40613
|
+
const box = encryptJson({ kind: "peer.denied" }, this.keyPair.secretKey, revokedPeer.publicKey);
|
|
40614
|
+
if (this.relay.sendPeerMessage(revokedPeer.runtimeId, box, "to-client")) {
|
|
40615
|
+
this._diagnostic("peer.denial_sent", { peer: peerRef(revokedPeer.runtimeId) });
|
|
40616
|
+
}
|
|
40617
|
+
}
|
|
40618
|
+
}
|
|
40540
40619
|
this._diagnostic("peer.message_rejected", {
|
|
40541
40620
|
reason: peer ? "key_mismatch" : "not_introduced",
|
|
40542
40621
|
peer: peerRef(event.sourceRuntimeId)
|
|
@@ -40730,7 +40809,7 @@ var require_headless_session_bridge = __commonJS({
|
|
|
40730
40809
|
};
|
|
40731
40810
|
}
|
|
40732
40811
|
var HeadlessSessionBridge = class {
|
|
40733
|
-
constructor({ runtime, remoteClient, peerRuntimeNetwork = null, dataPath, deliverMessage, createPairingLink = null, randomBytes = crypto.randomBytes } = {}) {
|
|
40812
|
+
constructor({ runtime, remoteClient, peerRuntimeNetwork = null, dataPath, deliverMessage, listLocalSessions = null, readLocalTranscript = null, createPairingLink = null, randomBytes = crypto.randomBytes } = {}) {
|
|
40734
40813
|
if (!runtime || !remoteClient || typeof deliverMessage !== "function" || !path.isAbsolute(dataPath || "")) {
|
|
40735
40814
|
throw new Error("CAS Cloud session bridge configuration is invalid");
|
|
40736
40815
|
}
|
|
@@ -40739,6 +40818,8 @@ var require_headless_session_bridge = __commonJS({
|
|
|
40739
40818
|
this.peerRuntimeNetwork = peerRuntimeNetwork;
|
|
40740
40819
|
this.dataPath = dataPath;
|
|
40741
40820
|
this.deliverMessage = deliverMessage;
|
|
40821
|
+
this.listLocalSessions = typeof listLocalSessions === "function" ? listLocalSessions : null;
|
|
40822
|
+
this.readLocalTranscript = typeof readLocalTranscript === "function" ? readLocalTranscript : null;
|
|
40742
40823
|
this.createPairingLink = createPairingLink;
|
|
40743
40824
|
this.adminToken = randomBytes(32).toString("hex");
|
|
40744
40825
|
this.sessionSecret = randomBytes(32);
|
|
@@ -40917,7 +40998,7 @@ var require_headless_session_bridge = __commonJS({
|
|
|
40917
40998
|
});
|
|
40918
40999
|
}
|
|
40919
41000
|
async _handle(request, response) {
|
|
40920
|
-
var _a, _b, _c;
|
|
41001
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
40921
41002
|
const url = new URL(request.url, "http://127.0.0.1");
|
|
40922
41003
|
if (url.pathname.startsWith("/admin/")) {
|
|
40923
41004
|
if (!safeBearer(request, this.adminToken)) return sendJson(response, 401, { error: "Unauthorized" });
|
|
@@ -40969,11 +41050,29 @@ var require_headless_session_bridge = __commonJS({
|
|
|
40969
41050
|
payload: {}
|
|
40970
41051
|
})
|
|
40971
41052
|
})));
|
|
40972
|
-
const
|
|
41053
|
+
const localSessions = (((_b = (_a = this.listLocalSessions) == null ? void 0 : _a.call(this)) == null ? void 0 : _b.sessions) || []).flatMap((session) => session && typeof session.id === "string" && session.id.length <= 128 ? [{
|
|
41054
|
+
id: session.id,
|
|
41055
|
+
name: clip(session.name, 120),
|
|
41056
|
+
agent: clip(session.agent, 60),
|
|
41057
|
+
project: clip(session.project, 160),
|
|
41058
|
+
agent_id: clip(session.agent_id, 60),
|
|
41059
|
+
project_icon: clip(session.project_icon, 140),
|
|
41060
|
+
project_color: clip(session.project_color, 32),
|
|
41061
|
+
goal: clip(session.goal, 1200),
|
|
41062
|
+
activity: clip(session.activity, 500),
|
|
41063
|
+
status: clip(session.status, 80),
|
|
41064
|
+
surface: session.surface === "terminal" ? "terminal" : "chat",
|
|
41065
|
+
state: ["working", "needs_input"].includes(session.state) ? session.state : "idle",
|
|
41066
|
+
is_current: session.id === sourceSessionId
|
|
41067
|
+
}] : []);
|
|
41068
|
+
const remoteSessions = results.flatMap((entry) => entry.status === "fulfilled" ? (({ state, result }) => (Array.isArray(result == null ? void 0 : result.sessions) ? result.sessions : []).slice(0, 100).flatMap((session) => session && typeof session.id === "string" && session.id.length <= 128 ? [{
|
|
40973
41069
|
id: encodeRemoteSessionId(state.runtime.id, session.id),
|
|
40974
41070
|
name: clip(session.name, 120),
|
|
40975
41071
|
agent: clip(session.agent, 60),
|
|
40976
41072
|
project: clip(session.project, 160),
|
|
41073
|
+
agent_id: clip(session.agent_id, 60),
|
|
41074
|
+
project_icon: clip(session.project_icon, 140),
|
|
41075
|
+
project_color: clip(session.project_color, 32),
|
|
40977
41076
|
goal: clip(session.goal, 1200),
|
|
40978
41077
|
activity: clip(session.activity, 500),
|
|
40979
41078
|
status: clip(session.status, 80),
|
|
@@ -40982,7 +41081,7 @@ var require_headless_session_bridge = __commonJS({
|
|
|
40982
41081
|
host: state.runtime.name || "Paired host",
|
|
40983
41082
|
is_current: false
|
|
40984
41083
|
}] : []))(entry.value) : []);
|
|
40985
|
-
return sendJson(response, 200, { sessions });
|
|
41084
|
+
return sendJson(response, 200, { sessions: [...localSessions, ...remoteSessions] });
|
|
40986
41085
|
} catch (_) {
|
|
40987
41086
|
return sendJson(response, 503, { error: "The paired Mac is offline" });
|
|
40988
41087
|
}
|
|
@@ -40993,6 +41092,25 @@ var require_headless_session_bridge = __commonJS({
|
|
|
40993
41092
|
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 60) {
|
|
40994
41093
|
return sendJson(response, 400, { error: "Conversation limit must be between 1 and 60" });
|
|
40995
41094
|
}
|
|
41095
|
+
if (this._sourceSession(body.target_session_id)) {
|
|
41096
|
+
if (!this.readLocalTranscript) return sendJson(response, 503, { error: "Conversation reading is unavailable" });
|
|
41097
|
+
try {
|
|
41098
|
+
const result = await this.readLocalTranscript({ targetSessionId: body.target_session_id, limit });
|
|
41099
|
+
const snapshot = boundedConversationMessages(result == null ? void 0 : result.messages, { limit });
|
|
41100
|
+
return sendJson(response, 200, {
|
|
41101
|
+
session: {
|
|
41102
|
+
id: body.target_session_id,
|
|
41103
|
+
name: clip((_c = result == null ? void 0 : result.session) == null ? void 0 : _c.name, 120),
|
|
41104
|
+
agent: clip((_d = result == null ? void 0 : result.session) == null ? void 0 : _d.agent, 60),
|
|
41105
|
+
project: clip((_e = result == null ? void 0 : result.session) == null ? void 0 : _e.project, 160)
|
|
41106
|
+
},
|
|
41107
|
+
messages: snapshot.messages,
|
|
41108
|
+
truncated: (result == null ? void 0 : result.truncated) === true || snapshot.truncated
|
|
41109
|
+
});
|
|
41110
|
+
} catch (_) {
|
|
41111
|
+
return sendJson(response, 503, { error: "The conversation could not be read" });
|
|
41112
|
+
}
|
|
41113
|
+
}
|
|
40996
41114
|
let target;
|
|
40997
41115
|
try {
|
|
40998
41116
|
target = decodeRemoteSessionId(body.target_session_id);
|
|
@@ -41011,9 +41129,9 @@ var require_headless_session_bridge = __commonJS({
|
|
|
41011
41129
|
return sendJson(response, 200, {
|
|
41012
41130
|
session: {
|
|
41013
41131
|
id: body.target_session_id,
|
|
41014
|
-
name: clip((
|
|
41015
|
-
agent: clip((
|
|
41016
|
-
project: clip((
|
|
41132
|
+
name: clip((_f = result == null ? void 0 : result.session) == null ? void 0 : _f.name, 120),
|
|
41133
|
+
agent: clip((_g = result == null ? void 0 : result.session) == null ? void 0 : _g.agent, 60),
|
|
41134
|
+
project: clip((_h = result == null ? void 0 : result.session) == null ? void 0 : _h.project, 160),
|
|
41017
41135
|
host: state.runtime.name || "Paired Mac"
|
|
41018
41136
|
},
|
|
41019
41137
|
messages: snapshot.messages,
|
|
@@ -41033,10 +41151,30 @@ var require_headless_session_bridge = __commonJS({
|
|
|
41033
41151
|
this._pruneReplies();
|
|
41034
41152
|
if (messageType === "response") {
|
|
41035
41153
|
const pending = this.pendingReplies.get(body.reply_to_request_id);
|
|
41036
|
-
if (!pending || pending.direction
|
|
41154
|
+
if (!pending || !["incoming", "local"].includes(pending.direction) || pending.sourceSessionId !== body.target_session_id || pending.targetSessionId !== sourceSessionId) {
|
|
41037
41155
|
return sendJson(response, 409, { error: "The response does not match an active session request" });
|
|
41038
41156
|
}
|
|
41039
41157
|
const source2 = this._sourceSession(sourceSessionId);
|
|
41158
|
+
if (pending.direction === "local") {
|
|
41159
|
+
try {
|
|
41160
|
+
const result = await this.deliverMessage({
|
|
41161
|
+
targetSessionId: pending.sourceSessionId,
|
|
41162
|
+
sourceSessionId,
|
|
41163
|
+
sourceName: (source2 == null ? void 0 : source2.title) || `${(source2 == null ? void 0 : source2.agent) || "CAS Cloud"} session`,
|
|
41164
|
+
sourceAgent: (source2 == null ? void 0 : source2.agent) || (source2 == null ? void 0 : source2.provider) || "agent",
|
|
41165
|
+
message: body.message.trim(),
|
|
41166
|
+
messageType: "response",
|
|
41167
|
+
communicationRequestId: body.reply_to_request_id
|
|
41168
|
+
});
|
|
41169
|
+
this.pendingReplies.delete(body.reply_to_request_id);
|
|
41170
|
+
return sendJson(response, 200, {
|
|
41171
|
+
success: true,
|
|
41172
|
+
status: (result == null ? void 0 : result.status) === "queued" ? "queued" : "delivered"
|
|
41173
|
+
});
|
|
41174
|
+
} catch (_) {
|
|
41175
|
+
return sendJson(response, 503, { error: "The session could not receive the response" });
|
|
41176
|
+
}
|
|
41177
|
+
}
|
|
41040
41178
|
if (!pending.reply({
|
|
41041
41179
|
sourceSessionId: pending.replyTargetSessionId,
|
|
41042
41180
|
targetSessionId: pending.remoteSourceSessionId,
|
|
@@ -41049,6 +41187,37 @@ var require_headless_session_bridge = __commonJS({
|
|
|
41049
41187
|
this.pendingReplies.delete(body.reply_to_request_id);
|
|
41050
41188
|
return sendJson(response, 200, { success: true, status: "delivered" });
|
|
41051
41189
|
}
|
|
41190
|
+
if (body.target_session_id === sourceSessionId) {
|
|
41191
|
+
return sendJson(response, 400, { error: "A session cannot message itself" });
|
|
41192
|
+
}
|
|
41193
|
+
const source = this._sourceSession(sourceSessionId);
|
|
41194
|
+
if (this._sourceSession(body.target_session_id)) {
|
|
41195
|
+
const communicationRequestId2 = crypto.randomUUID();
|
|
41196
|
+
this._rememberReply(communicationRequestId2, {
|
|
41197
|
+
direction: "local",
|
|
41198
|
+
sourceSessionId,
|
|
41199
|
+
targetSessionId: body.target_session_id
|
|
41200
|
+
});
|
|
41201
|
+
try {
|
|
41202
|
+
const result = await this.deliverMessage({
|
|
41203
|
+
targetSessionId: body.target_session_id,
|
|
41204
|
+
sourceSessionId,
|
|
41205
|
+
sourceName: (source == null ? void 0 : source.title) || `${(source == null ? void 0 : source.agent) || "CAS Cloud"} session`,
|
|
41206
|
+
sourceAgent: (source == null ? void 0 : source.agent) || (source == null ? void 0 : source.provider) || "agent",
|
|
41207
|
+
message: body.message.trim(),
|
|
41208
|
+
messageType: "request",
|
|
41209
|
+
communicationRequestId: communicationRequestId2
|
|
41210
|
+
});
|
|
41211
|
+
return sendJson(response, 200, {
|
|
41212
|
+
success: true,
|
|
41213
|
+
status: (result == null ? void 0 : result.status) === "queued" ? "queued" : "delivered",
|
|
41214
|
+
request_id: communicationRequestId2
|
|
41215
|
+
});
|
|
41216
|
+
} catch (_) {
|
|
41217
|
+
this.pendingReplies.delete(communicationRequestId2);
|
|
41218
|
+
return sendJson(response, 503, { error: "The session could not receive the request" });
|
|
41219
|
+
}
|
|
41220
|
+
}
|
|
41052
41221
|
let target;
|
|
41053
41222
|
try {
|
|
41054
41223
|
target = decodeRemoteSessionId(body.target_session_id);
|
|
@@ -41056,7 +41225,6 @@ var require_headless_session_bridge = __commonJS({
|
|
|
41056
41225
|
return sendJson(response, 400, { error: error.message });
|
|
41057
41226
|
}
|
|
41058
41227
|
if (!this._remoteClient(target.runtimeId)) return sendJson(response, 404, { error: "The remote session is unavailable" });
|
|
41059
|
-
const source = this._sourceSession(sourceSessionId);
|
|
41060
41228
|
const communicationRequestId = crypto.randomUUID();
|
|
41061
41229
|
this._rememberReply(communicationRequestId, {
|
|
41062
41230
|
direction: "outgoing",
|
|
@@ -41398,7 +41566,8 @@ var require_headless_project_registry = __commonJS({
|
|
|
41398
41566
|
onOperation = () => {
|
|
41399
41567
|
},
|
|
41400
41568
|
maxConcurrentClones = MAX_CLONES,
|
|
41401
|
-
stopTimeoutMs = 2e3
|
|
41569
|
+
stopTimeoutMs = 2e3,
|
|
41570
|
+
platform = process.platform
|
|
41402
41571
|
}) {
|
|
41403
41572
|
if (!(database == null ? void 0 : database.db)) throw new Error("HeadlessProjectRegistry requires a SQLite database");
|
|
41404
41573
|
this.database = database;
|
|
@@ -41409,6 +41578,7 @@ var require_headless_project_registry = __commonJS({
|
|
|
41409
41578
|
this.onOperation = onOperation;
|
|
41410
41579
|
this.maxConcurrentClones = maxConcurrentClones;
|
|
41411
41580
|
this.stopTimeoutMs = stopTimeoutMs;
|
|
41581
|
+
this.platform = platform;
|
|
41412
41582
|
this.stopping = false;
|
|
41413
41583
|
this.running = /* @__PURE__ */ new Map();
|
|
41414
41584
|
this.queue = [];
|
|
@@ -41527,6 +41697,19 @@ var require_headless_project_registry = __commonJS({
|
|
|
41527
41697
|
const result = this._registerPath(resolved, root ? this._rootByPath(root.rootPath).root_id : null, { legacy: true });
|
|
41528
41698
|
if (result.changed) changed = true;
|
|
41529
41699
|
}
|
|
41700
|
+
for (const row of this.db.prepare("SELECT project_id, path FROM runtime_projects WHERE registered = 1").all()) {
|
|
41701
|
+
let resolved;
|
|
41702
|
+
try {
|
|
41703
|
+
resolved = fs.realpathSync(row.path);
|
|
41704
|
+
} catch (_) {
|
|
41705
|
+
continue;
|
|
41706
|
+
}
|
|
41707
|
+
if (resolved === row.path) continue;
|
|
41708
|
+
const canonical = this.db.prepare("SELECT project_id FROM runtime_projects WHERE path = ? AND registered = 1").get(resolved);
|
|
41709
|
+
if (!canonical || canonical.project_id === row.project_id) continue;
|
|
41710
|
+
this.db.prepare("UPDATE runtime_projects SET registered = 0, updated_at = CURRENT_TIMESTAMP WHERE project_id = ?").run(row.project_id);
|
|
41711
|
+
changed = true;
|
|
41712
|
+
}
|
|
41530
41713
|
return changed;
|
|
41531
41714
|
}
|
|
41532
41715
|
_resolveDirectory(candidate, label) {
|
|
@@ -41588,7 +41771,7 @@ var require_headless_project_registry = __commonJS({
|
|
|
41588
41771
|
throw runtimeError("clone_root_insecure", "The configured clone root is not secure");
|
|
41589
41772
|
}
|
|
41590
41773
|
const effectiveUid = typeof process.geteuid === "function" ? process.geteuid() : null;
|
|
41591
|
-
if (!stat.isDirectory() || effectiveUid !== null && stat.uid !== effectiveUid || (stat.mode & 18) !== 0) {
|
|
41774
|
+
if (!stat.isDirectory() || this.platform !== "win32" && (effectiveUid !== null && stat.uid !== effectiveUid || (stat.mode & 18) !== 0)) {
|
|
41592
41775
|
throw runtimeError("clone_root_insecure", "The configured clone root is not secure");
|
|
41593
41776
|
}
|
|
41594
41777
|
return stat;
|
|
@@ -41635,6 +41818,46 @@ var require_headless_project_registry = __commonJS({
|
|
|
41635
41818
|
getRoots() {
|
|
41636
41819
|
return this.db.prepare("SELECT root_id, name FROM runtime_project_roots ORDER BY created_at, root_id").all().map((root) => ({ rootId: root.root_id, name: String(root.name).slice(0, 200) }));
|
|
41637
41820
|
}
|
|
41821
|
+
gitAvailability() {
|
|
41822
|
+
return new Promise((resolve) => {
|
|
41823
|
+
var _a, _b;
|
|
41824
|
+
let child;
|
|
41825
|
+
let output = "";
|
|
41826
|
+
let settled = false;
|
|
41827
|
+
const finish = (result) => {
|
|
41828
|
+
if (settled) return;
|
|
41829
|
+
settled = true;
|
|
41830
|
+
clearTimeout(timer);
|
|
41831
|
+
resolve(result);
|
|
41832
|
+
};
|
|
41833
|
+
const timer = setTimeout(() => {
|
|
41834
|
+
try {
|
|
41835
|
+
child == null ? void 0 : child.kill();
|
|
41836
|
+
} catch (_) {
|
|
41837
|
+
}
|
|
41838
|
+
finish({ available: false });
|
|
41839
|
+
}, 2e3);
|
|
41840
|
+
(_a = timer.unref) == null ? void 0 : _a.call(timer);
|
|
41841
|
+
try {
|
|
41842
|
+
child = this.spawnImpl("git", ["--version"], {
|
|
41843
|
+
shell: false,
|
|
41844
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
41845
|
+
windowsHide: true
|
|
41846
|
+
});
|
|
41847
|
+
(_b = child.stdout) == null ? void 0 : _b.on("data", (chunk) => {
|
|
41848
|
+
output = `${output}${String(chunk)}`.slice(0, 200);
|
|
41849
|
+
});
|
|
41850
|
+
child.once("error", () => finish({ available: false }));
|
|
41851
|
+
child.once("close", (code) => {
|
|
41852
|
+
var _a2;
|
|
41853
|
+
const version = (_a2 = /^git version\s+([^\s]+)/i.exec(output.trim())) == null ? void 0 : _a2[1];
|
|
41854
|
+
finish(code === 0 ? { available: true, ...version ? { version } : {} } : { available: false });
|
|
41855
|
+
});
|
|
41856
|
+
} catch (_) {
|
|
41857
|
+
finish({ available: false });
|
|
41858
|
+
}
|
|
41859
|
+
});
|
|
41860
|
+
}
|
|
41638
41861
|
listDirectories({ rootId, relativePath = "." } = {}) {
|
|
41639
41862
|
const root = this._root(rootId);
|
|
41640
41863
|
const currentPath = validateRelativePath(relativePath || ".");
|
|
@@ -41794,12 +42017,20 @@ var require_headless_project_registry = __commonJS({
|
|
|
41794
42017
|
const revision = this._bumpRevision();
|
|
41795
42018
|
return this._recordRequest(requestId, hash, { projectId: project.projectId, revision, updated: true });
|
|
41796
42019
|
}
|
|
41797
|
-
clone({ rootId, url, relativePath, requestId }) {
|
|
42020
|
+
clone({ rootId, url, relativePath, displayName, color, icon, requestId }) {
|
|
41798
42021
|
const normalizedUrl = validateGitUrl(url);
|
|
41799
42022
|
const root = this._root(rootId);
|
|
41800
42023
|
this._assertSecureCloneRoot(root);
|
|
41801
42024
|
const normalizedRelative = validateCloneChildName(relativePath || cloneDirectoryName(normalizedUrl));
|
|
41802
|
-
const
|
|
42025
|
+
const appearance = {
|
|
42026
|
+
...displayName !== void 0 ? { displayName: String(displayName || "").trim().slice(0, 120) } : {},
|
|
42027
|
+
...color !== void 0 ? { color: String(color || "").trim().slice(0, 32) } : {},
|
|
42028
|
+
...icon !== void 0 ? { icon } : {}
|
|
42029
|
+
};
|
|
42030
|
+
if (appearance.displayName !== void 0 && !appearance.displayName || appearance.icon !== void 0 && appearance.icon !== null && (typeof appearance.icon !== "string" || !ICON_PATTERN.test(appearance.icon))) {
|
|
42031
|
+
throw runtimeError("invalid_project_update", "Project changes are invalid");
|
|
42032
|
+
}
|
|
42033
|
+
const hash = requestHash("clone", { rootId, url: normalizedUrl, relativePath: normalizedRelative, ...appearance });
|
|
41803
42034
|
const duplicate = this._request(requestId, hash);
|
|
41804
42035
|
if (duplicate) return duplicate;
|
|
41805
42036
|
const destinationInfo = this._cloneDestination(root, normalizedRelative, normalizedUrl);
|
|
@@ -41816,6 +42047,7 @@ var require_headless_project_registry = __commonJS({
|
|
|
41816
42047
|
requestId,
|
|
41817
42048
|
rootId,
|
|
41818
42049
|
url: normalizedUrl,
|
|
42050
|
+
appearance,
|
|
41819
42051
|
destination: destinationInfo.destination,
|
|
41820
42052
|
temporaryDestination: null,
|
|
41821
42053
|
temporaryIdentity: null,
|
|
@@ -41953,7 +42185,17 @@ var require_headless_project_registry = __commonJS({
|
|
|
41953
42185
|
return this._finish(operation, "failed", "path_symlink_escape");
|
|
41954
42186
|
}
|
|
41955
42187
|
const registered = this._registerPath(resolved, root.root_id);
|
|
41956
|
-
|
|
42188
|
+
if (Object.keys(operation.appearance).length) {
|
|
42189
|
+
this.db.prepare(`UPDATE runtime_projects
|
|
42190
|
+
SET display_name = COALESCE(?, display_name), color = COALESCE(?, color), icon = ?, updated_at = CURRENT_TIMESTAMP
|
|
42191
|
+
WHERE project_id = ?`).run(
|
|
42192
|
+
operation.appearance.displayName ?? null,
|
|
42193
|
+
operation.appearance.color ?? null,
|
|
42194
|
+
operation.appearance.icon === void 0 ? registered.row.icon || null : operation.appearance.icon,
|
|
42195
|
+
registered.row.project_id
|
|
42196
|
+
);
|
|
42197
|
+
}
|
|
42198
|
+
const revision = registered.changed || Object.keys(operation.appearance).length ? this._bumpRevision() : this.getRevision();
|
|
41957
42199
|
this.db.prepare(`UPDATE runtime_project_operations SET state = 'succeeded', project_id = ?, error = NULL, updated_at = CURRENT_TIMESTAMP WHERE operation_id = ?`).run(registered.row.project_id, operation.operationId);
|
|
41958
42200
|
this.running.delete(operation.operationId);
|
|
41959
42201
|
this.destinations.delete(operation.destination);
|
|
@@ -42035,6 +42277,7 @@ var require_headless_project_registry = __commonJS({
|
|
|
42035
42277
|
contained,
|
|
42036
42278
|
runtimeError,
|
|
42037
42279
|
validateGitUrl,
|
|
42280
|
+
cloneDirectoryName,
|
|
42038
42281
|
validateCloneChildName,
|
|
42039
42282
|
validateRelativePath
|
|
42040
42283
|
};
|
|
@@ -49241,6 +49484,8 @@ var require_headless_runtime = __commonJS({
|
|
|
49241
49484
|
var os = require("os");
|
|
49242
49485
|
var path = require("path");
|
|
49243
49486
|
var { DriverChatManager, SESSION_EVENT } = require_driver_chat_manager();
|
|
49487
|
+
var { CHAT_PERMISSION_MODES } = require_chat_permission_modes();
|
|
49488
|
+
var { classifyProviderStartupError } = require_provider_auth();
|
|
49244
49489
|
var { boundedConversationMessages } = require_chat_history_pagination();
|
|
49245
49490
|
var { MobileRuntime } = require_mobile_runtime();
|
|
49246
49491
|
var { MobileRelayClient } = require_mobile_relay_client();
|
|
@@ -49290,6 +49535,7 @@ var require_headless_runtime = __commonJS({
|
|
|
49290
49535
|
"project.register",
|
|
49291
49536
|
"project.clone",
|
|
49292
49537
|
"project.clone.cancel",
|
|
49538
|
+
"project.git.availability",
|
|
49293
49539
|
"project.unregister",
|
|
49294
49540
|
"shortcuts.manage",
|
|
49295
49541
|
"session.action",
|
|
@@ -49314,18 +49560,11 @@ var require_headless_runtime = __commonJS({
|
|
|
49314
49560
|
"workspace.git.switch",
|
|
49315
49561
|
"workspace.git.create"
|
|
49316
49562
|
]);
|
|
49317
|
-
var FINAL_COORDINATION_STATUSES = /* @__PURE__ */ new Set(["done", "pushed", "completed", "finished"]);
|
|
49318
|
-
var COORDINATION_IDLE_MS = 30 * 6e4;
|
|
49319
49563
|
var COORDINATION_COMPLETION_GRACE_MS = 5e3;
|
|
49320
|
-
function isCoordinatedSessionEligible(session
|
|
49321
|
-
|
|
49322
|
-
|
|
49323
|
-
|
|
49324
|
-
if (FINAL_COORDINATION_STATUSES.has(status)) return false;
|
|
49325
|
-
if (((_a = session.currentTurn) == null ? void 0 : _a.state) === "running" || status === "needs_input" || status === "working") return true;
|
|
49326
|
-
const lastActivity = Number(session.lastActivityAt) || Date.parse(session.lastActivityAt);
|
|
49327
|
-
if (Number.isFinite(lastActivity) && now - lastActivity > COORDINATION_IDLE_MS) return false;
|
|
49328
|
-
return Array.from(((_c = (_b = session.items) == null ? void 0 : _b.values) == null ? void 0 : _c.call(_b)) || []).some((item) => (item == null ? void 0 : item.itemType) === "user_message" || (item == null ? void 0 : item.itemType) === "assistant_message");
|
|
49564
|
+
function isCoordinatedSessionEligible(session) {
|
|
49565
|
+
return Boolean(
|
|
49566
|
+
session && session.state !== "stopped" && typeof session.terminalUuid === "string" && session.terminalUuid
|
|
49567
|
+
);
|
|
49329
49568
|
}
|
|
49330
49569
|
function appDataPath({ env = process.env, platform = process.platform, home = os.homedir() } = {}) {
|
|
49331
49570
|
if (platform === "linux") {
|
|
@@ -49581,7 +49820,8 @@ var require_headless_runtime = __commonJS({
|
|
|
49581
49820
|
quotaService: suppliedQuotaService = null,
|
|
49582
49821
|
generateConversationTitle: generateConversationTitleFn = generateConversationTitle,
|
|
49583
49822
|
forkConversation: forkConversationFn = forkConversation,
|
|
49584
|
-
spawnImpl
|
|
49823
|
+
spawnImpl,
|
|
49824
|
+
getuid = typeof process.getuid === "function" ? () => process.getuid() : null
|
|
49585
49825
|
} = {}) {
|
|
49586
49826
|
if (typeof getToken !== "function") throw new Error("CAS CLI requires an access token provider");
|
|
49587
49827
|
if (!validIdentity(identity)) throw new Error("CAS CLI identity is invalid");
|
|
@@ -49623,7 +49863,17 @@ var require_headless_runtime = __commonJS({
|
|
|
49623
49863
|
const startSessionWithPreferences = async (options) => {
|
|
49624
49864
|
const launchOptions = chatPreferences.apply(options.agent, options);
|
|
49625
49865
|
if (launchOptions.permissionMode === void 0) launchOptions.permissionMode = "default";
|
|
49626
|
-
|
|
49866
|
+
if (options.agent === "claude" && launchOptions.permissionMode === CHAT_PERMISSION_MODES.FULL_ACCESS && (getuid == null ? void 0 : getuid()) === 0) launchOptions.permissionMode = "default";
|
|
49867
|
+
let started;
|
|
49868
|
+
try {
|
|
49869
|
+
started = await manager.startSession(launchOptions);
|
|
49870
|
+
} catch (error) {
|
|
49871
|
+
const status = classifyProviderStartupError(options.agent, error);
|
|
49872
|
+
if (status) {
|
|
49873
|
+
error.code = status.state === "not_installed" ? "provider_not_installed" : "provider_unauthenticated";
|
|
49874
|
+
}
|
|
49875
|
+
throw error;
|
|
49876
|
+
}
|
|
49627
49877
|
chatPreferences.write(started.agent || options.agent, {
|
|
49628
49878
|
permissionMode: started.permissionMode,
|
|
49629
49879
|
effort: started.effort
|
|
@@ -49769,17 +50019,20 @@ var require_headless_runtime = __commonJS({
|
|
|
49769
50019
|
};
|
|
49770
50020
|
const listCoordinatedSessions = () => ({
|
|
49771
50021
|
sessions: Array.from(runtime.sessions.values()).flatMap((session) => {
|
|
49772
|
-
var _a, _b;
|
|
50022
|
+
var _a, _b, _c, _d;
|
|
49773
50023
|
return isCoordinatedSessionEligible(session) ? [{
|
|
49774
50024
|
id: session.terminalUuid,
|
|
49775
50025
|
name: session.title || `${session.agent || "Agent"} session`,
|
|
49776
50026
|
agent: session.agent || session.provider || "",
|
|
50027
|
+
agent_id: session.agent || session.provider || "",
|
|
49777
50028
|
project: ((_a = session.project) == null ? void 0 : _a.name) || "",
|
|
50029
|
+
project_icon: ((_b = session.project) == null ? void 0 : _b.icon) || "",
|
|
50030
|
+
project_color: ((_c = session.project) == null ? void 0 : _c.color) || "",
|
|
49778
50031
|
goal: session.goal || "",
|
|
49779
50032
|
activity: session.activity || "",
|
|
49780
50033
|
status: session.workStatus || "",
|
|
49781
50034
|
surface: "chat",
|
|
49782
|
-
state: session.workStatus === "needs_input" ? "needs_input" : ((
|
|
50035
|
+
state: session.workStatus === "needs_input" ? "needs_input" : ((_d = session.currentTurn) == null ? void 0 : _d.state) === "running" ? "working" : "idle"
|
|
49783
50036
|
}] : [];
|
|
49784
50037
|
}).slice(0, 100)
|
|
49785
50038
|
});
|
|
@@ -50053,6 +50306,7 @@ ${message}`;
|
|
|
50053
50306
|
registerProject: (payload) => registry.register(payload),
|
|
50054
50307
|
cloneProject: (payload) => registry.clone(payload),
|
|
50055
50308
|
cancelProjectClone: (payload) => registry.cancelClone(payload),
|
|
50309
|
+
gitAvailability: () => registry.gitAvailability(),
|
|
50056
50310
|
unregisterProject: (payload) => {
|
|
50057
50311
|
const busy = startingProjects.has(payload.projectId) || Array.from(runtime.sessions.values()).some((session) => {
|
|
50058
50312
|
var _a;
|
|
@@ -50129,6 +50383,8 @@ ${message}`;
|
|
|
50129
50383
|
peerRuntimeNetwork,
|
|
50130
50384
|
dataPath: resolvedDataPath,
|
|
50131
50385
|
deliverMessage: deliverCoordinatedMessage,
|
|
50386
|
+
listLocalSessions: listCoordinatedSessions,
|
|
50387
|
+
readLocalTranscript: readCoordinatedTranscript,
|
|
50132
50388
|
createPairingLink: async () => {
|
|
50133
50389
|
const pairing = await relay.createPairing();
|
|
50134
50390
|
return { url: desktopConnectionLink(pairing), expiresAt: pairing.expiresAt };
|
|
@@ -50175,7 +50431,7 @@ ${message}`;
|
|
|
50175
50431
|
}
|
|
50176
50432
|
terminalOrder = Math.max(terminalOrder, saved.terminalOrder || 0);
|
|
50177
50433
|
try {
|
|
50178
|
-
const started = await
|
|
50434
|
+
const started = await startSessionWithPreferences({
|
|
50179
50435
|
agent: saved.agent,
|
|
50180
50436
|
...saved.accountId && saved.accountId !== "current" ? { accountId: saved.accountId } : {},
|
|
50181
50437
|
cwd: saved.cwd,
|
|
@@ -50586,6 +50842,9 @@ var require_mobile_pairing_ipc = __commonJS({
|
|
|
50586
50842
|
"use strict";
|
|
50587
50843
|
var MOBILE_PAIRING_EVENT = "mobile-pairing:event";
|
|
50588
50844
|
var { PRODUCTION_MOBILE_WEB_ORIGIN } = require_mobile_build_channel();
|
|
50845
|
+
var WARM_PAIRING_MIN_REMAINING_MS = 2 * 6e4;
|
|
50846
|
+
var WARM_PAIRING_CHECK_INTERVAL_MS = 3e4;
|
|
50847
|
+
var WARM_PAIRING_SERVE_MIN_REMAINING_MS = 15e3;
|
|
50589
50848
|
function pairingPayload(pairing, mobileWebOrigin = PRODUCTION_MOBILE_WEB_ORIGIN) {
|
|
50590
50849
|
const credentials = new URL("codeagentswarm://pair");
|
|
50591
50850
|
credentials.searchParams.set("relay", new URL(pairing.relayOrigin).origin);
|
|
@@ -50607,13 +50866,49 @@ var require_mobile_pairing_ipc = __commonJS({
|
|
|
50607
50866
|
setKeepAvailable = () => false,
|
|
50608
50867
|
createQrDataUrl = (payload, options) => require("qrcode").toDataURL(payload, options)
|
|
50609
50868
|
}) {
|
|
50869
|
+
var _a;
|
|
50610
50870
|
const broadcast = (message) => {
|
|
50611
50871
|
for (const window2 of BrowserWindow.getAllWindows()) {
|
|
50612
50872
|
if (!window2.isDestroyed()) window2.webContents.send(MOBILE_PAIRING_EVENT, message);
|
|
50613
50873
|
}
|
|
50614
50874
|
};
|
|
50615
|
-
|
|
50616
|
-
|
|
50875
|
+
const buildPairing = async () => {
|
|
50876
|
+
const pairing = await relayClient.createPairing();
|
|
50877
|
+
const qrDataUrl = await createQrDataUrl(
|
|
50878
|
+
pairingPayload(pairing, mobileWebOrigin),
|
|
50879
|
+
{
|
|
50880
|
+
scale: 8,
|
|
50881
|
+
margin: 4,
|
|
50882
|
+
errorCorrectionLevel: "L",
|
|
50883
|
+
color: { dark: "#111827", light: "#ffffff" }
|
|
50884
|
+
}
|
|
50885
|
+
);
|
|
50886
|
+
return { expiresAt: pairing.expiresAt, pairingCode: pairing.pairingCode, qrDataUrl };
|
|
50887
|
+
};
|
|
50888
|
+
let warm = null;
|
|
50889
|
+
let warming = null;
|
|
50890
|
+
const warmPairing = () => {
|
|
50891
|
+
if (warming || relayClient.status !== "online") return warming;
|
|
50892
|
+
const remaining = warm ? warm.expiresAt - Date.now() : 0;
|
|
50893
|
+
if (warm && (warm.served ? remaining > 0 : remaining > WARM_PAIRING_MIN_REMAINING_MS)) return null;
|
|
50894
|
+
warming = buildPairing().then((result) => {
|
|
50895
|
+
warm = result;
|
|
50896
|
+
}, () => {
|
|
50897
|
+
}).finally(() => {
|
|
50898
|
+
warming = null;
|
|
50899
|
+
});
|
|
50900
|
+
return warming;
|
|
50901
|
+
};
|
|
50902
|
+
const warmTimer = setInterval(warmPairing, WARM_PAIRING_CHECK_INTERVAL_MS);
|
|
50903
|
+
(_a = warmTimer.unref) == null ? void 0 : _a.call(warmTimer);
|
|
50904
|
+
relayClient.on("status", (status) => {
|
|
50905
|
+
broadcast({ type: "status", status });
|
|
50906
|
+
if ((status == null ? void 0 : status.status) === "online") void warmPairing();
|
|
50907
|
+
});
|
|
50908
|
+
relayClient.on("event", (event) => {
|
|
50909
|
+
if ((event == null ? void 0 : event.kind) === "pair.scanned") warm = null;
|
|
50910
|
+
broadcast({ type: "relay", event });
|
|
50911
|
+
});
|
|
50617
50912
|
ipcMain.handle("mobile-pairing:status", () => ({
|
|
50618
50913
|
success: true,
|
|
50619
50914
|
...relayClient.getStatus(),
|
|
@@ -50645,23 +50940,16 @@ var require_mobile_pairing_ipc = __commonJS({
|
|
|
50645
50940
|
ipcMain.handle("mobile-pairing:create", async () => {
|
|
50646
50941
|
try {
|
|
50647
50942
|
if (getKeepAvailable() == null) setKeepAvailable(true);
|
|
50648
|
-
|
|
50649
|
-
|
|
50650
|
-
|
|
50651
|
-
{
|
|
50652
|
-
scale: 8,
|
|
50653
|
-
margin: 4,
|
|
50654
|
-
errorCorrectionLevel: "L",
|
|
50655
|
-
color: { dark: "#111827", light: "#ffffff" }
|
|
50656
|
-
}
|
|
50657
|
-
);
|
|
50943
|
+
if (warming) await warming;
|
|
50944
|
+
if (!warm || warm.expiresAt - Date.now() < WARM_PAIRING_SERVE_MIN_REMAINING_MS) warm = await buildPairing();
|
|
50945
|
+
warm.served = true;
|
|
50658
50946
|
return {
|
|
50659
50947
|
success: true,
|
|
50660
|
-
expiresAt:
|
|
50661
|
-
pairingCode:
|
|
50948
|
+
expiresAt: warm.expiresAt,
|
|
50949
|
+
pairingCode: warm.pairingCode,
|
|
50662
50950
|
webUrl: mobileWebOrigin,
|
|
50663
50951
|
keepAvailable: getKeepAvailable() === true,
|
|
50664
|
-
qrDataUrl
|
|
50952
|
+
qrDataUrl: warm.qrDataUrl
|
|
50665
50953
|
};
|
|
50666
50954
|
} catch (error) {
|
|
50667
50955
|
return { success: false, error: error.message };
|
|
@@ -50707,7 +50995,7 @@ var require_cas = __commonJS({
|
|
|
50707
50995
|
loadIdentity,
|
|
50708
50996
|
resolveProject
|
|
50709
50997
|
} = require_headless_runtime();
|
|
50710
|
-
var version = true ? "0.0.
|
|
50998
|
+
var version = true ? "0.0.16" : JSON.parse(fs.readFileSync(path.join(__dirname, "..", "..", "package.json"), "utf8")).version;
|
|
50711
50999
|
function help() {
|
|
50712
51000
|
return `CAS CLI ${version}
|
|
50713
51001
|
|