chatroom-cli 1.98.7 → 1.99.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/build/assets/index-DKoewUK4.css +1 -0
- package/dist/client/build/assets/{index-6IhLktfo.js → index-LbWoI4E4.js} +23 -23
- package/dist/client/build/index.html +2 -2
- package/dist/index.js +838 -609
- package/dist/index.js.map +55 -47
- package/package.json +1 -1
- package/dist/client/build/assets/index-TiUlJQMc.css +0 -1
package/dist/index.js
CHANGED
|
@@ -78980,19 +78980,19 @@ function getDelegationBriefIntro() {
|
|
|
78980
78980
|
var HANDOFF_NOT_APPLICABLE_EXACT_TEXT = "Not Applicable.";
|
|
78981
78981
|
|
|
78982
78982
|
// ../../services/backend/prompts/utils/handoff-quality-principles.ts
|
|
78983
|
-
function getHandoffQualityPrinciplesTemplateBlock() {
|
|
78983
|
+
function getHandoffQualityPrinciplesTemplateBlock(subject = "work") {
|
|
78984
78984
|
const lines = HANDOFF_QUALITY_PRINCIPLES.flatMap((p) => [
|
|
78985
|
-
`- **${p.name}:** <how this
|
|
78985
|
+
`- **${p.name}:** <how this ${subject} demonstrates ${p.name.toLowerCase()}, or exactly "${HANDOFF_NOT_APPLICABLE_EXACT_TEXT}">`,
|
|
78986
78986
|
`<!-- ${p.name}: ${p.description} -->`,
|
|
78987
78987
|
""
|
|
78988
78988
|
]);
|
|
78989
78989
|
return lines.join(`
|
|
78990
78990
|
`).trimEnd();
|
|
78991
78991
|
}
|
|
78992
|
-
function getHandoffQualityPrinciplesSectionBlock() {
|
|
78992
|
+
function getHandoffQualityPrinciplesSectionBlock(subject = "work") {
|
|
78993
78993
|
return `${PROOF_OF_PRINCIPLES_HEADING_H2}
|
|
78994
78994
|
${PROOF_OF_PRINCIPLES_MANDATORY_COMMENT}
|
|
78995
|
-
${getHandoffQualityPrinciplesTemplateBlock()}`;
|
|
78995
|
+
${getHandoffQualityPrinciplesTemplateBlock(subject)}`;
|
|
78996
78996
|
}
|
|
78997
78997
|
var HANDOFF_QUALITY_PRINCIPLES, PROOF_OF_PRINCIPLES_HEADING_H2 = "## Proof of Principles", PROOF_OF_PRINCIPLES_MANDATORY_COMMENT;
|
|
78998
78998
|
var init_handoff_quality_principles = __esm(() => {
|
|
@@ -79087,163 +79087,195 @@ var init_builder_to_planner = __esm(() => {
|
|
|
79087
79087
|
init_role_guidance_disclosure();
|
|
79088
79088
|
});
|
|
79089
79089
|
|
|
79090
|
-
// ../../services/backend/
|
|
79091
|
-
|
|
79092
|
-
return [
|
|
79093
|
-
"### Defragmentation workflow checklist",
|
|
79094
|
-
'Complete the optional **Defragmentation** section when the planner check-in addresses a large or multi-surface system revision, including refactoring, consolidation, or consistency work. Write exactly "Not Applicable." only when no such revision is proposed.',
|
|
79095
|
-
"",
|
|
79096
|
-
"1. **Study surfaces** — map all call sites, use cases, and complexity variants before proposing slices; name every relevant file/module",
|
|
79097
|
-
"2. **Golden implementation** — build a standalone canonical solution first; introduce canonical domain entities/types only when the studied variants require them, then shared use cases, UI components, or utilities; do not patch duplicates in place",
|
|
79098
|
-
"3. **Migrate callers** — refactor all consumers to the golden path; each slice must be shippable end-to-end",
|
|
79099
|
-
"4. **Delete legacy** — remove old implementations only after migration is complete; no dead-code leftovers",
|
|
79100
|
-
"",
|
|
79101
|
-
"### Anti-patterns to flag",
|
|
79102
|
-
"- Incremental copy-paste fixes across N files without a golden SSOT",
|
|
79103
|
-
"- New abstraction without studying all existing variants",
|
|
79104
|
-
'- Leaving old code "for safety" after migration',
|
|
79105
|
-
"- Slices that add helpers/infra without a runnable end-to-end outcome",
|
|
79106
|
-
"- Parallel implementations coexisting without a deletion plan",
|
|
79107
|
-
"",
|
|
79108
|
-
"### Structural decisions",
|
|
79109
|
-
"- Identify SSOT locations for domain entities, shared use cases, and UI components",
|
|
79110
|
-
"- Align with `structural-decisions` glossary: folder structure, file naming, interface locations",
|
|
79111
|
-
"- Flag when the plan scatters the canonical implementation across unrelated modules"
|
|
79112
|
-
].join(`
|
|
79113
|
-
`);
|
|
79114
|
-
}
|
|
79090
|
+
// ../../services/backend/src/domain/usecase/enhancer/enhancer-handoff-content.ts
|
|
79091
|
+
var ENHANCER_USER_MESSAGE_PLACEHOLDER = "{{USER_MESSAGE}}";
|
|
79115
79092
|
|
|
79116
|
-
// ../../services/backend/prompts/
|
|
79117
|
-
function
|
|
79118
|
-
return
|
|
79119
|
-
|
|
79120
|
-
|
|
79121
|
-
|
|
79122
|
-
|
|
79123
|
-
|
|
79124
|
-
|
|
79125
|
-
|
|
79126
|
-
|
|
79127
|
-
|
|
79128
|
-
|
|
79129
|
-
"8. **Interaction affordance** — clickable/interactive elements use pointer cursor (or the project's established equivalent) where applicable?",
|
|
79130
|
-
"9. **Destructive actions** — irreversible or high-impact single actions gated by confirmation?",
|
|
79131
|
-
"10. **Bulk actions** — batch/multi-item operations confirmed with scope or impact summary?",
|
|
79132
|
-
"",
|
|
79133
|
-
"### Review principles",
|
|
79134
|
-
"- Ground feedback in the planner check-in and the project codebase — cite existing patterns rather than inventing generic UI preferences.",
|
|
79135
|
-
"- Flag missing states, layout-shift risk, and missing interaction affordances when the plan omits them; recommend consistency with established project conventions.",
|
|
79136
|
-
"- Do **not** prescribe style choices the project has not adopted (e.g. specific flex layouts, canonical card chrome, responsive utility patterns, button label copy).",
|
|
79137
|
-
"- When multiple valid patterns exist in the codebase, recommend one and explain the tradeoff."
|
|
79138
|
-
].join(`
|
|
79139
|
-
`);
|
|
79093
|
+
// ../../services/backend/prompts/utils/frontend-design-ux-checklist.ts
|
|
79094
|
+
function getFrontendDesignUxPlanningPrinciplesBlock() {
|
|
79095
|
+
return `<!-- Ground every flow in user history and repository patterns. Recommend one existing pattern when multiple exist; do not prescribe style choices the project has not adopted. -->`;
|
|
79096
|
+
}
|
|
79097
|
+
function getFrontendDesignUxFlowChecklistBlock() {
|
|
79098
|
+
return `**UX quality (complete for every interactive step in this flow):**
|
|
79099
|
+
- **States:** loading | empty | error | success — no blank panels, silent failures, or missing retry affordances
|
|
79100
|
+
- **Layout:** stable across async transitions — no layout shift when content arrives or state changes
|
|
79101
|
+
- **Patterns:** consistent with existing project components — cite the chosen pattern and repo-relative file
|
|
79102
|
+
- **Shortcuts:** aligned with project keyboard/shortcut conventions; document tab order and gaps
|
|
79103
|
+
- **Feedback:** timely response for async user actions
|
|
79104
|
+
- **Interaction affordance:** pointer cursor (or project equivalent) on clickable elements
|
|
79105
|
+
- **Safeguards:** confirmation before destructive actions; bulk operations confirmed with scope summary`;
|
|
79140
79106
|
}
|
|
79141
79107
|
|
|
79142
79108
|
// ../../services/backend/prompts/utils/enhancer-feedback-template-body.ts
|
|
79143
79109
|
function getEnhancerFeedbackTemplateBody() {
|
|
79144
79110
|
return `<handoff-overview>
|
|
79145
79111
|
## Summary
|
|
79146
|
-
<
|
|
79112
|
+
<one paragraph: what we're building and the single design direction>
|
|
79147
79113
|
|
|
79148
|
-
## User intent
|
|
79149
|
-
<
|
|
79114
|
+
## User intent and constraints
|
|
79115
|
+
<explicit requirements from user messages; hard constraints that must not be violated>
|
|
79150
79116
|
</handoff-overview>
|
|
79151
79117
|
|
|
79152
|
-
<!-- UI collapses proofs, direction,
|
|
79118
|
+
<!-- UI collapses proofs, direction, frontend design, data design, and notes by default; overview and action required are expanded -->
|
|
79153
79119
|
|
|
79154
79120
|
<handoff-proofs>
|
|
79155
|
-
##
|
|
79156
|
-
<
|
|
79121
|
+
## Repository evidence
|
|
79122
|
+
<files read, current behavior verified, patterns reused — cite repo-relative paths and short snippets only>
|
|
79123
|
+
|
|
79124
|
+
${getHandoffQualityPrinciplesSectionBlock("design")}
|
|
79157
79125
|
</handoff-proofs>
|
|
79158
79126
|
|
|
79159
79127
|
<handoff-direction>
|
|
79160
|
-
##
|
|
79161
|
-
|
|
79128
|
+
## Recommended design
|
|
79129
|
+
<!-- ONE design only. No Option A/B/C. -->
|
|
79130
|
+
|
|
79131
|
+
<2–4 sentences: the chosen architecture and why it fits the request and existing system>
|
|
79162
79132
|
</handoff-direction>
|
|
79163
79133
|
|
|
79164
|
-
<handoff-
|
|
79165
|
-
|
|
79166
|
-
<!-- When UI is proposed: specific findings tied to the planner's proposal. No code blocks (use Suggested edits). -->
|
|
79167
|
-
- **Flows:** <click count, nested modals, simpler alternatives>
|
|
79168
|
-
- **Patterns:** <consistency with existing project components; recommend one when multiple>
|
|
79169
|
-
- **Layout:** <complexity, wrappers, layout stable across state transitions — no layout shift>
|
|
79170
|
-
- **Shortcuts:** <alignment with catalog; gaps or conflicts>
|
|
79171
|
-
- **States:** <loading/error/empty explicitly handled; no blank panels or silent failures>
|
|
79172
|
-
- **Error boundaries:** <error boundary placement; failure isolated from the whole app>
|
|
79173
|
-
- **Feedback:** <timely response for async actions>
|
|
79174
|
-
- **Interaction affordance:** <pointer cursor or project equivalent on clickable elements where applicable>
|
|
79175
|
-
- **Destructive safeguards:** <confirmation before irreversible/high-impact actions>
|
|
79176
|
-
- **Bulk safeguards:** <confirmation with scope summary for batch operations>
|
|
79177
|
-
</handoff-ux>
|
|
79178
|
-
|
|
79179
|
-
<handoff-defragmentation>
|
|
79180
|
-
<!-- Optional — write exactly "Not Applicable." when no large or multi-surface system revision is proposed -->
|
|
79181
|
-
<!-- When revision work is proposed: specific findings tied to the planner's proposal. No code blocks (use Suggested edits). -->
|
|
79182
|
-
- **Surfaces:** <call sites and modules identified; gaps in surface mapping>
|
|
79183
|
-
- **Golden path:** <whether planner builds standalone canonical implementation first>
|
|
79184
|
-
- **Domain model:** <canonical types/entities needed or "not needed">
|
|
79185
|
-
- **Shared components:** <shared abstractions planned (use cases, UI, utilities)>
|
|
79186
|
-
- **Slice ordering:** <study → golden → migrate → delete sequence respected?>
|
|
79187
|
-
- **Migration plan:** <how all callers move to golden path>
|
|
79188
|
-
- **Deletion plan:** <old implementations slated for removal>
|
|
79189
|
-
- **Duplication:** <existing duplicates to eliminate; risk of new duplication>
|
|
79190
|
-
- **Structural decisions:** <folder/module boundaries; SSOT locations>
|
|
79191
|
-
</handoff-defragmentation>
|
|
79134
|
+
<handoff-frontend-design>
|
|
79135
|
+
## Frontend / user-centric design
|
|
79192
79136
|
|
|
79193
|
-
|
|
79194
|
-
## Knowledge gaps
|
|
79195
|
-
<specific facts, files, or research to verify — name what to check and why>
|
|
79196
|
-
</handoff-notes>
|
|
79137
|
+
${getFrontendDesignUxPlanningPrinciplesBlock()}
|
|
79197
79138
|
|
|
79198
|
-
<
|
|
79199
|
-
|
|
79200
|
-
<specific risks tied to this plan — what fails, under what conditions, and how to mitigate>
|
|
79139
|
+
### Flow 1: <name>
|
|
79140
|
+
**Entry:** User visits \`<route/page>\` from \`<source>\`.
|
|
79201
79141
|
|
|
79202
|
-
|
|
79203
|
-
|
|
79142
|
+
| Step | User action | System response | UI state |
|
|
79143
|
+
|------|-------------|-----------------|----------|
|
|
79144
|
+
| 1 | User clicks \`<element label>\` | \`<navigation / modal / fetch>\` | \`<loading → success/error>\` |
|
|
79204
79145
|
|
|
79205
|
-
|
|
79206
|
-
|
|
79207
|
-
|
|
79208
|
-
|
|
79146
|
+
${getFrontendDesignUxFlowChecklistBlock()}
|
|
79147
|
+
|
|
79148
|
+
**Expected interactions per element:**
|
|
79149
|
+
- \`<ElementName>\` (\`apps/webapp/src/...\`): click → \`<handler>\`; keyboard: \`<tab order>\`; disabled when \`<condition>\`
|
|
79150
|
+
|
|
79151
|
+
### Element, style, and layout specification
|
|
79152
|
+
|
|
79153
|
+
#### \`<ComponentName>\` — \`apps/webapp/src/path/to/Component.tsx\`
|
|
79154
|
+
**Change:** <create | modify>
|
|
79155
|
+
|
|
79156
|
+
**Layout:** \`<div className="...">\` — flex/grid, gaps, breakpoints
|
|
79157
|
+
|
|
79158
|
+
**States:** loading | empty | error | success
|
|
79159
|
+
|
|
79160
|
+
\`\`\`tsx
|
|
79161
|
+
export function ComponentName({ ... }: Props) {
|
|
79162
|
+
// target structure — props, classNames, branches
|
|
79163
|
+
}
|
|
79164
|
+
\`\`\`
|
|
79165
|
+
|
|
79166
|
+
<!-- Repeat per component; write exactly "Not Applicable." for the entire section if no UI -->
|
|
79167
|
+
</handoff-frontend-design>
|
|
79168
|
+
|
|
79169
|
+
<handoff-data-design>
|
|
79170
|
+
## Persistent state and query pattern design
|
|
79171
|
+
|
|
79172
|
+
**Goal:** Small updates must not cause large cache invalidations. High-frequency writes use projections to smaller tables.
|
|
79209
79173
|
|
|
79210
|
-
###
|
|
79211
|
-
|
|
79212
|
-
|
|
79174
|
+
### 1. Sources of concern
|
|
79175
|
+
| Source | Write frequency | Read pattern | Risk |
|
|
79176
|
+
|--------|---------------|--------------|------|
|
|
79177
|
+
| \`<table/mutation>\` | \`<frequency>\` | \`<pattern>\` | \`<scan / hot partition>\` |
|
|
79178
|
+
|
|
79179
|
+
### 2. Schema design
|
|
79180
|
+
**Hot path:** \`<table>\` — fields, projection from \`<source>\`
|
|
79181
|
+
**Cold path:** \`<table>\` — …
|
|
79182
|
+
|
|
79183
|
+
\`\`\`typescript
|
|
79184
|
+
// target schema shape
|
|
79185
|
+
\`\`\`
|
|
79186
|
+
|
|
79187
|
+
### 3. Index design (within limits)
|
|
79188
|
+
| Table | Index | Serves query | Budget |
|
|
79189
|
+
|-------|-------|--------------|--------|
|
|
79190
|
+
|
|
79191
|
+
### 4. Query design (within limits)
|
|
79192
|
+
| Query | Index | Rows scanned | Timeout | Invalidation scope |
|
|
79193
|
+
|-------|-------|--------------|---------|-------------------|
|
|
79213
79194
|
|
|
79214
79195
|
\`\`\`typescript
|
|
79215
|
-
//
|
|
79196
|
+
// target query signature
|
|
79216
79197
|
\`\`\`
|
|
79217
79198
|
|
|
79218
|
-
|
|
79199
|
+
<!-- Write exactly "Not Applicable." for the entire section if no persistence changes -->
|
|
79200
|
+
</handoff-data-design>
|
|
79201
|
+
|
|
79202
|
+
<handoff-notes>
|
|
79203
|
+
## Open questions for user
|
|
79204
|
+
<decisions only the user can make, or write "Not Applicable.">
|
|
79205
|
+
</handoff-notes>
|
|
79206
|
+
|
|
79207
|
+
<handoff-action>
|
|
79208
|
+
## Recommended implementation sequence
|
|
79209
|
+
<!-- Ordered slices for the planner — references files from design sections. For large or multi-surface revisions, activate the defragmentation skill before delegating. -->
|
|
79210
|
+
|
|
79211
|
+
1. …
|
|
79212
|
+
2. …
|
|
79213
|
+
|
|
79214
|
+
## Files touched (index)
|
|
79215
|
+
- \`apps/webapp/src/...\` — …
|
|
79216
|
+
- \`services/backend/convex/...\` — …
|
|
79219
79217
|
</handoff-action>`;
|
|
79220
79218
|
}
|
|
79221
|
-
var init_enhancer_feedback_template_body = () => {
|
|
79219
|
+
var init_enhancer_feedback_template_body = __esm(() => {
|
|
79220
|
+
init_handoff_quality_principles();
|
|
79221
|
+
});
|
|
79222
79222
|
|
|
79223
|
-
// ../../services/backend/prompts/
|
|
79224
|
-
function
|
|
79225
|
-
return
|
|
79223
|
+
// ../../services/backend/prompts/enhancer/handoff-templates.ts
|
|
79224
|
+
function roleLabel(role) {
|
|
79225
|
+
return role.charAt(0).toUpperCase() + role.slice(1).toLowerCase();
|
|
79226
|
+
}
|
|
79227
|
+
function getEntryPointToEnhancerHandoffTemplate(entryPointRole) {
|
|
79228
|
+
const label = roleLabel(entryPointRole);
|
|
79229
|
+
return `**Planning Request (${label} → Enhancer)** — after reading the user message and any pinned chatroom context, fill only <additional-context> below. The system injects the user message automatically — do not copy it.
|
|
79226
79230
|
|
|
79227
|
-
|
|
79231
|
+
\`\`\`markdown
|
|
79232
|
+
<user-message>
|
|
79233
|
+
<!-- Injected automatically from the originating user message — do not edit or copy the user message here -->
|
|
79234
|
+
${ENHANCER_USER_MESSAGE_PLACEHOLDER}
|
|
79235
|
+
</user-message>
|
|
79228
79236
|
|
|
79229
|
-
|
|
79237
|
+
<additional-context>
|
|
79238
|
+
## Goal
|
|
79239
|
+
<what the user wants in plain language — one short paragraph>
|
|
79240
|
+
</additional-context>
|
|
79241
|
+
\`\`\`
|
|
79230
79242
|
|
|
79231
|
-
|
|
79243
|
+
After handoff succeeds, **end your turn immediately**. The enhancer independently downloads the originating message history and returns design input as your next ${entryPointRole.toLowerCase()} task.`;
|
|
79244
|
+
}
|
|
79245
|
+
function getEnhancerToEntryPointHandoffTemplate(entryPointRole) {
|
|
79246
|
+
const normalizedRole = entryPointRole.toLowerCase();
|
|
79247
|
+
const label = roleLabel(entryPointRole);
|
|
79248
|
+
return `**Design Input (Enhancer → ${label})**
|
|
79232
79249
|
|
|
79233
|
-
${
|
|
79250
|
+
You are the design authority for this request. Recover conversation history, inspect the repository, and return **one** complete design — not options. The ${normalizedRole} agent verifies your design and delegates implementation.
|
|
79234
79251
|
|
|
79235
|
-
|
|
79252
|
+
**Rules:**
|
|
79253
|
+
- Design first — complete frontend and data/query sections before implementation sequencing.
|
|
79254
|
+
- **No alternative approaches** — one \`Recommended design\` only.
|
|
79255
|
+
- Frontend and data sections: code granularity (component names, props, classes, file paths, schema, indexes, queries).
|
|
79256
|
+
- Complete per-flow **UX quality** checklist in frontend design — states, layout stability, patterns, safeguards.
|
|
79257
|
+
- For large or multi-surface revisions, note in implementation sequence that the entry point should activate the \`defragmentation\` skill.
|
|
79258
|
+
- In \`<handoff-proofs>\`, complete **Proof of Principles** for how this design satisfies each quality principle (or "Not Applicable.").
|
|
79259
|
+
- Write "Not Applicable." only when a major design section truly does not apply.
|
|
79236
79260
|
|
|
79237
79261
|
\`\`\`markdown
|
|
79238
79262
|
${getEnhancerFeedbackTemplateBody()}
|
|
79239
79263
|
\`\`\`
|
|
79240
79264
|
|
|
79241
|
-
Return only the
|
|
79265
|
+
Return only the design input markdown — no preamble. Follow this structure; use "Not Applicable." where a major section does not apply.`;
|
|
79242
79266
|
}
|
|
79243
|
-
var
|
|
79267
|
+
var init_handoff_templates = __esm(() => {
|
|
79244
79268
|
init_enhancer_feedback_template_body();
|
|
79245
79269
|
});
|
|
79246
79270
|
|
|
79271
|
+
// ../../services/backend/prompts/teams/duo/handoff-templates/enhancer-to-planner.ts
|
|
79272
|
+
function getEnhancerToPlannerHandoffTemplate() {
|
|
79273
|
+
return getEnhancerToEntryPointHandoffTemplate("planner");
|
|
79274
|
+
}
|
|
79275
|
+
var init_enhancer_to_planner = __esm(() => {
|
|
79276
|
+
init_handoff_templates();
|
|
79277
|
+
});
|
|
79278
|
+
|
|
79247
79279
|
// ../../services/backend/prompts/teams/duo/handoff-templates/planner-to-builder.ts
|
|
79248
79280
|
function getPlannerToBuilderHandoffTemplate() {
|
|
79249
79281
|
return `${getHandoffRecipientVisibilityCallout("builder")}
|
|
@@ -79322,40 +79354,11 @@ var init_planner_to_builder = () => {};
|
|
|
79322
79354
|
|
|
79323
79355
|
// ../../services/backend/prompts/teams/duo/handoff-templates/planner-to-enhancer.ts
|
|
79324
79356
|
function getPlannerToEnhancerHandoffTemplate() {
|
|
79325
|
-
return
|
|
79326
|
-
|
|
79327
|
-
**Mandatory Planning Check-in (Planner → Enhancer)** — paste into the handoff message. **Do not skip this check-in** when the enhancer is enabled.
|
|
79328
|
-
|
|
79329
|
-
The enhancer starts from this check-in — it may read files in the repo to verify your grounding. Use the three XML sections below **exactly** — they delimit what the enhancer will review.
|
|
79330
|
-
|
|
79331
|
-
\`\`\`markdown
|
|
79332
|
-
<user-message>
|
|
79333
|
-
<verbatim or faithful quote of the user's request — include constraints, priorities, and classification context if relevant>
|
|
79334
|
-
</user-message>
|
|
79335
|
-
|
|
79336
|
-
<grounding>
|
|
79337
|
-
<fully detailed research — include file paths and snippets the enhancer should verify; it may read the codebase to validate your proposal>
|
|
79338
|
-
|
|
79339
|
-
Include:
|
|
79340
|
-
- **Existing code examples** — relevant snippets, patterns, and conventions already in the codebase
|
|
79341
|
-
- **File references** — paths to every file you investigated or plan to change
|
|
79342
|
-
- **Technology choices** — libraries, frameworks, APIs, and why they apply here
|
|
79343
|
-
- **Observations** — what you learned, edge cases, risks, and open questions from investigation
|
|
79344
|
-
${getFileReferenceGuidanceComment()}
|
|
79345
|
-
</grounding>
|
|
79346
|
-
|
|
79347
|
-
<builder-handoff>
|
|
79348
|
-
<your complete, filled-in Delegation Brief for builder review — every section with real content, not placeholders>
|
|
79349
|
-
|
|
79350
|
-
Follow the **Handoff to \`builder\`** template structure (Summary, Goal, approach, Requirements, etc.). The enhancer reviews **approach and scope** — not line-by-line file edits. Keep file references for context, but expect advisory feedback on risks and gaps, not a rewritten brief.
|
|
79351
|
-
</builder-handoff>
|
|
79352
|
-
\`\`\`
|
|
79353
|
-
|
|
79354
|
-
After handoff succeeds, **end your turn immediately** — do not monitor the enhancer or wait in this session. When review completes, enhancer → planner handoff delivers feedback as your next planner task.
|
|
79355
|
-
|
|
79356
|
-
After you receive that feedback, you make the **final call** — incorporate valid critiques, ignore what doesn't apply, then proceed to \`builder\` or \`user\`. Do not re-check with the enhancer for this slice; one round only.`;
|
|
79357
|
+
return getEntryPointToEnhancerHandoffTemplate("planner");
|
|
79357
79358
|
}
|
|
79358
|
-
var init_planner_to_enhancer = () => {
|
|
79359
|
+
var init_planner_to_enhancer = __esm(() => {
|
|
79360
|
+
init_handoff_templates();
|
|
79361
|
+
});
|
|
79359
79362
|
|
|
79360
79363
|
// ../../services/backend/prompts/utils/context-disclosure.ts
|
|
79361
79364
|
function getContextReadDisclosureComment(params = {}) {
|
|
@@ -79533,7 +79536,7 @@ function getDuoHandoffTemplate(query) {
|
|
|
79533
79536
|
return getter?.(query) ?? null;
|
|
79534
79537
|
}
|
|
79535
79538
|
var DUO_HANDOFF_TEMPLATES;
|
|
79536
|
-
var
|
|
79539
|
+
var init_handoff_templates2 = __esm(() => {
|
|
79537
79540
|
init_builder_to_planner();
|
|
79538
79541
|
init_enhancer_to_planner();
|
|
79539
79542
|
init_planner_to_builder();
|
|
@@ -79576,9 +79579,12 @@ function getSoloHandoffTemplate(query) {
|
|
|
79576
79579
|
return getter?.(query) ?? null;
|
|
79577
79580
|
}
|
|
79578
79581
|
var SOLO_HANDOFF_TEMPLATES;
|
|
79579
|
-
var
|
|
79582
|
+
var init_handoff_templates3 = __esm(() => {
|
|
79580
79583
|
init_solo_to_user();
|
|
79584
|
+
init_handoff_templates();
|
|
79581
79585
|
SOLO_HANDOFF_TEMPLATES = {
|
|
79586
|
+
"solo:enhancer": () => getEntryPointToEnhancerHandoffTemplate("solo"),
|
|
79587
|
+
"enhancer:solo": () => getEnhancerToEntryPointHandoffTemplate("solo"),
|
|
79582
79588
|
"solo:user": (query) => getSoloToUserReportTemplate({
|
|
79583
79589
|
chatroomId: query.chatroomId,
|
|
79584
79590
|
role: query.role,
|
|
@@ -79596,9 +79602,9 @@ function getHandoffTemplate(query) {
|
|
|
79596
79602
|
return getSoloHandoffTemplate(query);
|
|
79597
79603
|
return null;
|
|
79598
79604
|
}
|
|
79599
|
-
var
|
|
79600
|
-
init_handoff_templates();
|
|
79605
|
+
var init_handoff_templates4 = __esm(() => {
|
|
79601
79606
|
init_handoff_templates2();
|
|
79607
|
+
init_handoff_templates3();
|
|
79602
79608
|
});
|
|
79603
79609
|
|
|
79604
79610
|
// ../../services/backend/prompts/cli/handoff/view-template.ts
|
|
@@ -79615,7 +79621,7 @@ function viewHandoffTemplate(params) {
|
|
|
79615
79621
|
return template;
|
|
79616
79622
|
}
|
|
79617
79623
|
var init_view_template2 = __esm(() => {
|
|
79618
|
-
|
|
79624
|
+
init_handoff_templates4();
|
|
79619
79625
|
});
|
|
79620
79626
|
|
|
79621
79627
|
// src/commands/handoff/view-template.ts
|
|
@@ -79780,9 +79786,12 @@ function formatDecodeError(error) {
|
|
|
79780
79786
|
|
|
79781
79787
|
// ../../services/backend/prompts/native/session-continuity.ts
|
|
79782
79788
|
function getNativeHandoffTurnEndGuidance(nextRole) {
|
|
79789
|
+
return getHandoffTurnEndGuidance(nextRole);
|
|
79790
|
+
}
|
|
79791
|
+
function getHandoffTurnEndGuidance(nextRole) {
|
|
79783
79792
|
const lines = [
|
|
79784
79793
|
"",
|
|
79785
|
-
"**Handoff
|
|
79794
|
+
"**Handoff complete. End your turn now — stop tool calls. The system will send you a message when further action is required.**"
|
|
79786
79795
|
];
|
|
79787
79796
|
if (nextRole.toLowerCase() === "user") {
|
|
79788
79797
|
lines.push("The system delivers the next chatroom task when the user sends one.");
|
|
@@ -79792,11 +79801,11 @@ function getNativeHandoffTurnEndGuidance(nextRole) {
|
|
|
79792
79801
|
return lines.join(`
|
|
79793
79802
|
`);
|
|
79794
79803
|
}
|
|
79795
|
-
function
|
|
79804
|
+
function getNativeEnhancerRequestTurnEndGuidance() {
|
|
79796
79805
|
return [
|
|
79797
79806
|
"",
|
|
79798
|
-
"**Handoff
|
|
79799
|
-
"Do **not** wait for enhancer
|
|
79807
|
+
"**Handoff complete. End your turn now — stop tool calls. The system will send you a message when further action is required.**",
|
|
79808
|
+
"Do **not** wait for enhancer input, poll, or monitor the enhancer job in this turn. The system delivers independent planning input as your next task when analysis completes."
|
|
79800
79809
|
].join(`
|
|
79801
79810
|
`);
|
|
79802
79811
|
}
|
|
@@ -79826,10 +79835,14 @@ var init_backlog = __esm(() => {
|
|
|
79826
79835
|
// ../../services/backend/src/domain/usecase/skills/modules/code-review/index.ts
|
|
79827
79836
|
var init_code_review = () => {};
|
|
79828
79837
|
|
|
79838
|
+
// ../../services/backend/src/domain/usecase/skills/modules/defragmentation/index.ts
|
|
79839
|
+
var init_defragmentation = () => {};
|
|
79840
|
+
|
|
79829
79841
|
// ../../services/backend/src/domain/usecase/skills/registry.ts
|
|
79830
79842
|
var init_registry4 = __esm(() => {
|
|
79831
79843
|
init_backlog();
|
|
79832
79844
|
init_code_review();
|
|
79845
|
+
init_defragmentation();
|
|
79833
79846
|
});
|
|
79834
79847
|
|
|
79835
79848
|
// ../../services/backend/prompts/sections/glossary.ts
|
|
@@ -79866,7 +79879,8 @@ var init_glossary = __esm(() => {
|
|
|
79866
79879
|
},
|
|
79867
79880
|
{
|
|
79868
79881
|
term: "structural-decisions",
|
|
79869
|
-
definition: "Meta-level architectural choices that persist in the codebase and influence consistency: " + "folder structure, file naming, interface definitions, and key abstraction names/locations " + "(e.g., Repository/Service layers)."
|
|
79882
|
+
definition: "Meta-level architectural choices that persist in the codebase and influence consistency: " + "folder structure, file naming, interface definitions, and key abstraction names/locations " + "(e.g., Repository/Service layers).",
|
|
79883
|
+
linkedSkillId: "defragmentation"
|
|
79870
79884
|
}
|
|
79871
79885
|
];
|
|
79872
79886
|
NATIVE_GLOSSARY_TERMS = [
|
|
@@ -80225,15 +80239,15 @@ var init_types = __esm(() => {
|
|
|
80225
80239
|
// ../../services/backend/prompts/review-guidelines/index.ts
|
|
80226
80240
|
var init_review_guidelines = () => {};
|
|
80227
80241
|
// ../../services/backend/prompts/generator.ts
|
|
80228
|
-
function
|
|
80229
|
-
return params.
|
|
80242
|
+
function isEnhancerRequestQueuedHandoff(params) {
|
|
80243
|
+
return params.enhancerRequestQueued === true && params.nextRole.toLowerCase() === "enhancer";
|
|
80230
80244
|
}
|
|
80231
|
-
function
|
|
80232
|
-
const turnEndRule = nativeIntegration ? "**End your turn now
|
|
80245
|
+
function getEnhancerRequestQueuedConfirmationLines(nativeIntegration) {
|
|
80246
|
+
const turnEndRule = nativeIntegration ? "**Handoff complete. End your turn now — stop tool calls. The system will send you a message when further action is required.** Do **not** wait for enhancer input, poll, monitor the enhancer, or re-submit the handoff. The system delivers independent planning input as your next task when analysis completes." : "**Run get-next-task now and end your turn — stop tool calls. The system will send you a message when further action is required.** Do **not** wait for enhancer input, poll, monitor the enhancer, or re-submit the handoff.";
|
|
80233
80247
|
return [
|
|
80234
|
-
"✅
|
|
80248
|
+
"✅ User request queued for handoff enhancer",
|
|
80235
80249
|
"",
|
|
80236
|
-
"
|
|
80250
|
+
"The user request was sent to the handoff enhancer (async). You will receive independent planning input as your next task when analysis completes.",
|
|
80237
80251
|
turnEndRule
|
|
80238
80252
|
];
|
|
80239
80253
|
}
|
|
@@ -80244,24 +80258,28 @@ function generateHandoffOutput(params) {
|
|
|
80244
80258
|
chatroomId,
|
|
80245
80259
|
convexUrl,
|
|
80246
80260
|
supportsNativeIntegration,
|
|
80247
|
-
|
|
80261
|
+
enhancerRequestQueued
|
|
80248
80262
|
} = params;
|
|
80249
80263
|
const cliEnvPrefix = getCliEnvPrefix(convexUrl);
|
|
80250
|
-
const
|
|
80264
|
+
const enhancerRequest = isEnhancerRequestQueuedHandoff({
|
|
80265
|
+
nextRole,
|
|
80266
|
+
enhancerRequestQueued
|
|
80267
|
+
});
|
|
80251
80268
|
const lines = [];
|
|
80252
|
-
if (
|
|
80253
|
-
lines.push(...
|
|
80269
|
+
if (enhancerRequest) {
|
|
80270
|
+
lines.push(...getEnhancerRequestQueuedConfirmationLines(supportsNativeIntegration));
|
|
80254
80271
|
} else {
|
|
80255
80272
|
lines.push(`✅ Chatroom task completed and handed off to ${nextRole}`);
|
|
80256
80273
|
}
|
|
80257
80274
|
if (supportsNativeIntegration) {
|
|
80258
|
-
lines.push(
|
|
80275
|
+
lines.push(enhancerRequest ? getNativeEnhancerRequestTurnEndGuidance() : getNativeHandoffTurnEndGuidance(nextRole));
|
|
80259
80276
|
} else {
|
|
80260
80277
|
lines.push("");
|
|
80261
80278
|
lines.push("✅ Level B complete (chatroom task handed off).");
|
|
80262
80279
|
lines.push("⏳ Level A continues (session is still active) — run get-next-task to stay connected:");
|
|
80263
80280
|
lines.push("");
|
|
80264
80281
|
lines.push(`\`${getNextTaskCommand({ chatroomId, role, cliEnvPrefix })}\``);
|
|
80282
|
+
lines.push(getHandoffTurnEndGuidance(nextRole));
|
|
80265
80283
|
}
|
|
80266
80284
|
return lines.join(`
|
|
80267
80285
|
`);
|
|
@@ -80419,7 +80437,7 @@ var handoffEffect = (chatroomId, options) => exports_Effect.gen(function* () {
|
|
|
80419
80437
|
chatroomId,
|
|
80420
80438
|
convexUrl,
|
|
80421
80439
|
supportsNativeIntegration: result.supportsNativeIntegration,
|
|
80422
|
-
|
|
80440
|
+
enhancerRequestQueued: result.enhancerJobId != null
|
|
80423
80441
|
}));
|
|
80424
80442
|
});
|
|
80425
80443
|
});
|
|
@@ -83515,6 +83533,321 @@ function harnessCapabilitiesFingerprint(harnesses, versions) {
|
|
|
83515
83533
|
return `${h}::${v3}`;
|
|
83516
83534
|
}
|
|
83517
83535
|
|
|
83536
|
+
// src/daemon/infrastructure/outbox/lib/durable-fifo-queue-schema.ts
|
|
83537
|
+
var DURABLE_FIFO_QUEUE_MIGRATIONS;
|
|
83538
|
+
var init_durable_fifo_queue_schema = __esm(() => {
|
|
83539
|
+
DURABLE_FIFO_QUEUE_MIGRATIONS = [
|
|
83540
|
+
`CREATE TABLE IF NOT EXISTS schema_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)`,
|
|
83541
|
+
`CREATE TABLE IF NOT EXISTS fifo_outbox_entries (id INTEGER PRIMARY KEY AUTOINCREMENT, delivery_key TEXT NOT NULL, payload_json TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'pending', attempts INTEGER NOT NULL DEFAULT 0, last_error TEXT, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL)`,
|
|
83542
|
+
`CREATE INDEX IF NOT EXISTS idx_fifo_outbox_pending ON fifo_outbox_entries(delivery_key, status, id)`
|
|
83543
|
+
];
|
|
83544
|
+
});
|
|
83545
|
+
|
|
83546
|
+
// src/daemon/infrastructure/outbox/lib/durable-fifo-queue-store.ts
|
|
83547
|
+
import { DatabaseSync } from "node:sqlite";
|
|
83548
|
+
import { mkdirSync as mkdirSync4 } from "node:fs";
|
|
83549
|
+
import { dirname as dirname9 } from "node:path";
|
|
83550
|
+
function openDurableFifoQueueStore(dbPath) {
|
|
83551
|
+
mkdirSync4(dirname9(dbPath), { recursive: true });
|
|
83552
|
+
const db = new DatabaseSync(dbPath);
|
|
83553
|
+
for (const sql of DURABLE_FIFO_QUEUE_MIGRATIONS)
|
|
83554
|
+
db.exec(sql);
|
|
83555
|
+
db.prepare("UPDATE fifo_outbox_entries SET status='pending', updated_at=? WHERE status='in_flight'").run(Date.now());
|
|
83556
|
+
return {
|
|
83557
|
+
enqueue: (key, payloadJson) => {
|
|
83558
|
+
const now = Date.now();
|
|
83559
|
+
return Number(db.prepare("INSERT INTO fifo_outbox_entries(delivery_key,payload_json,created_at,updated_at) VALUES(?,?,?,?) RETURNING id").get(key, payloadJson, now, now).id);
|
|
83560
|
+
},
|
|
83561
|
+
claimNextBatch: (key, limit) => db.prepare("UPDATE fifo_outbox_entries SET status='in_flight', attempts=attempts+1, updated_at=? WHERE id IN (SELECT id FROM fifo_outbox_entries WHERE delivery_key=? AND status='pending' ORDER BY id LIMIT ?) RETURNING id, delivery_key as deliveryKey, payload_json as payloadJson, attempts").all(Date.now(), key, limit),
|
|
83562
|
+
markDone: (id3) => {
|
|
83563
|
+
db.prepare("DELETE FROM fifo_outbox_entries WHERE id=?").run(id3);
|
|
83564
|
+
},
|
|
83565
|
+
markPending: (id3) => {
|
|
83566
|
+
db.prepare("UPDATE fifo_outbox_entries SET status='pending', last_error=NULL, updated_at=? WHERE id=?").run(Date.now(), id3);
|
|
83567
|
+
},
|
|
83568
|
+
updatePayload: (id3, payloadJson) => {
|
|
83569
|
+
db.prepare("UPDATE fifo_outbox_entries SET payload_json=?, updated_at=? WHERE id=?").run(payloadJson, Date.now(), id3);
|
|
83570
|
+
},
|
|
83571
|
+
markPendingRetry: (id3, error) => {
|
|
83572
|
+
db.prepare("UPDATE fifo_outbox_entries SET status='pending', last_error=?, updated_at=? WHERE id=?").run(String(error), Date.now(), id3);
|
|
83573
|
+
},
|
|
83574
|
+
listPendingForRecovery: (key) => db.prepare("SELECT id, delivery_key as deliveryKey, payload_json as payloadJson, attempts FROM fifo_outbox_entries WHERE delivery_key=? AND status IN ('pending','in_flight') ORDER BY id").all(key),
|
|
83575
|
+
close: () => db.close()
|
|
83576
|
+
};
|
|
83577
|
+
}
|
|
83578
|
+
var init_durable_fifo_queue_store = __esm(() => {
|
|
83579
|
+
init_durable_fifo_queue_schema();
|
|
83580
|
+
});
|
|
83581
|
+
|
|
83582
|
+
// src/daemon/infrastructure/outbox/lib/outbox-retry-backoff.ts
|
|
83583
|
+
function computeExponentialRetryDelayMs(attempt, retryDelayMs, maxRetryDelayMs) {
|
|
83584
|
+
const exponent = Math.min(Math.max(0, attempt), MAX_RETRY_EXPONENT);
|
|
83585
|
+
return Math.min(retryDelayMs * 2 ** exponent, maxRetryDelayMs);
|
|
83586
|
+
}
|
|
83587
|
+
var MAX_RETRY_EXPONENT = 20;
|
|
83588
|
+
|
|
83589
|
+
// src/daemon/infrastructure/outbox/lib/fifo-batched-outbox.ts
|
|
83590
|
+
function createFifoBatchedOutbox(o) {
|
|
83591
|
+
const waiters = new Map;
|
|
83592
|
+
let running3;
|
|
83593
|
+
let stopped = false;
|
|
83594
|
+
let retryTimer;
|
|
83595
|
+
let retryAttempt = 0;
|
|
83596
|
+
const retryDelay = () => computeExponentialRetryDelayMs(retryAttempt++, o.retryDelayMs ?? 500, o.maxRetryDelayMs ?? 5000);
|
|
83597
|
+
const scheduleRetry = () => {
|
|
83598
|
+
if (!stopped && !retryTimer) {
|
|
83599
|
+
retryTimer = setTimeout(() => {
|
|
83600
|
+
retryTimer = undefined;
|
|
83601
|
+
drain().catch(() => {
|
|
83602
|
+
return;
|
|
83603
|
+
});
|
|
83604
|
+
}, retryDelay());
|
|
83605
|
+
retryTimer.unref?.();
|
|
83606
|
+
}
|
|
83607
|
+
};
|
|
83608
|
+
const drain = async () => {
|
|
83609
|
+
if (running3)
|
|
83610
|
+
return running3;
|
|
83611
|
+
running3 = (async () => {
|
|
83612
|
+
while (true) {
|
|
83613
|
+
const rows = o.store.claimNextBatch(o.deliveryKey, o.batchSize);
|
|
83614
|
+
if (!rows.length)
|
|
83615
|
+
break;
|
|
83616
|
+
try {
|
|
83617
|
+
const results = await o.send(rows.map((r) => o.deserialize(r.payloadJson)));
|
|
83618
|
+
let hasRetry = false;
|
|
83619
|
+
for (let i2 = 0;i2 < results.length; i2++) {
|
|
83620
|
+
const item = o.deserialize(rows[i2].payloadJson);
|
|
83621
|
+
const outcome = o.classifyOutcome?.(results[i2], item) ?? { kind: "success" };
|
|
83622
|
+
if (outcome.kind === "retry") {
|
|
83623
|
+
o.store.updatePayload(rows[i2].id, o.serialize(outcome.item));
|
|
83624
|
+
o.store.markPending(rows[i2].id);
|
|
83625
|
+
hasRetry = true;
|
|
83626
|
+
continue;
|
|
83627
|
+
}
|
|
83628
|
+
o.store.markDone(rows[i2].id);
|
|
83629
|
+
waiters.get(rows[i2].id)?.resolve(results[i2]);
|
|
83630
|
+
waiters.delete(rows[i2].id);
|
|
83631
|
+
}
|
|
83632
|
+
for (let i2 = results.length;i2 < rows.length; i2++)
|
|
83633
|
+
o.store.markPending(rows[i2].id);
|
|
83634
|
+
if (hasRetry) {
|
|
83635
|
+
scheduleRetry();
|
|
83636
|
+
break;
|
|
83637
|
+
}
|
|
83638
|
+
retryAttempt = 0;
|
|
83639
|
+
} catch (e) {
|
|
83640
|
+
o.onError?.(e);
|
|
83641
|
+
for (const r of rows)
|
|
83642
|
+
o.store.markPendingRetry(r.id, e);
|
|
83643
|
+
scheduleRetry();
|
|
83644
|
+
break;
|
|
83645
|
+
}
|
|
83646
|
+
}
|
|
83647
|
+
})().finally(() => {
|
|
83648
|
+
running3 = undefined;
|
|
83649
|
+
});
|
|
83650
|
+
return running3;
|
|
83651
|
+
};
|
|
83652
|
+
const enqueue = (item) => {
|
|
83653
|
+
if (stopped)
|
|
83654
|
+
return Promise.reject(new Error("Outbox is stopped"));
|
|
83655
|
+
const id3 = o.store.enqueue(o.deliveryKey, o.serialize(item));
|
|
83656
|
+
const p = new Promise((resolve4, reject) => waiters.set(id3, { resolve: resolve4, reject }));
|
|
83657
|
+
drain().catch(() => {
|
|
83658
|
+
return;
|
|
83659
|
+
});
|
|
83660
|
+
return p;
|
|
83661
|
+
};
|
|
83662
|
+
const flushNow = async () => {
|
|
83663
|
+
while (o.store.listPendingForRecovery(o.deliveryKey).length) {
|
|
83664
|
+
await drain();
|
|
83665
|
+
}
|
|
83666
|
+
};
|
|
83667
|
+
const stop4 = async () => {
|
|
83668
|
+
if (stopped)
|
|
83669
|
+
return;
|
|
83670
|
+
if (retryTimer)
|
|
83671
|
+
clearTimeout(retryTimer);
|
|
83672
|
+
retryTimer = undefined;
|
|
83673
|
+
await flushNow();
|
|
83674
|
+
stopped = true;
|
|
83675
|
+
};
|
|
83676
|
+
return { enqueue, flushNow, stop: stop4 };
|
|
83677
|
+
}
|
|
83678
|
+
var init_fifo_batched_outbox = () => {};
|
|
83679
|
+
|
|
83680
|
+
// src/daemon/infrastructure/outbox/lib/keyed-fifo-batched-outbox-registry.ts
|
|
83681
|
+
function createKeyedFifoBatchedOutboxRegistry(o) {
|
|
83682
|
+
const boxes = new Map;
|
|
83683
|
+
const get13 = (key) => {
|
|
83684
|
+
let b = boxes.get(key);
|
|
83685
|
+
if (!b) {
|
|
83686
|
+
b = createFifoBatchedOutbox({
|
|
83687
|
+
batchSize: o.batchSize,
|
|
83688
|
+
send: o.createSend(key),
|
|
83689
|
+
store: o.store,
|
|
83690
|
+
deliveryKey: key,
|
|
83691
|
+
serialize: o.serialize,
|
|
83692
|
+
deserialize: o.deserialize,
|
|
83693
|
+
retryDelayMs: o.retryDelayMs,
|
|
83694
|
+
maxRetryDelayMs: o.maxRetryDelayMs,
|
|
83695
|
+
onError: (e) => o.onError?.(key, e),
|
|
83696
|
+
classifyOutcome: o.classifyOutcome
|
|
83697
|
+
});
|
|
83698
|
+
boxes.set(key, b);
|
|
83699
|
+
}
|
|
83700
|
+
return b;
|
|
83701
|
+
};
|
|
83702
|
+
const stop4 = async (k) => {
|
|
83703
|
+
const b = boxes.get(k);
|
|
83704
|
+
if (b) {
|
|
83705
|
+
await b.stop();
|
|
83706
|
+
boxes.delete(k);
|
|
83707
|
+
}
|
|
83708
|
+
};
|
|
83709
|
+
return {
|
|
83710
|
+
enqueue: (k, i2) => get13(k).enqueue(i2),
|
|
83711
|
+
flushNow: async (k) => {
|
|
83712
|
+
if (k)
|
|
83713
|
+
await get13(k).flushNow();
|
|
83714
|
+
else
|
|
83715
|
+
for (const b of boxes.values())
|
|
83716
|
+
await b.flushNow();
|
|
83717
|
+
},
|
|
83718
|
+
stop: stop4,
|
|
83719
|
+
stopAll: async () => {
|
|
83720
|
+
for (const k of [...boxes.keys()])
|
|
83721
|
+
await stop4(k);
|
|
83722
|
+
o.store.close();
|
|
83723
|
+
}
|
|
83724
|
+
};
|
|
83725
|
+
}
|
|
83726
|
+
var init_keyed_fifo_batched_outbox_registry = __esm(() => {
|
|
83727
|
+
init_fifo_batched_outbox();
|
|
83728
|
+
});
|
|
83729
|
+
|
|
83730
|
+
// src/daemon/infrastructure/outbox/outbox-db-path.ts
|
|
83731
|
+
import { homedir as homedir5 } from "node:os";
|
|
83732
|
+
import { join as join17 } from "node:path";
|
|
83733
|
+
function resolveOutboxDbPath(machineId, kind) {
|
|
83734
|
+
return join17(homedir5(), ".chatroom", "daemon", machineId, `outbox-${kind}.sqlite`);
|
|
83735
|
+
}
|
|
83736
|
+
var init_outbox_db_path = () => {};
|
|
83737
|
+
|
|
83738
|
+
// src/daemon/domain/entities/agent-lifecycle-fact.ts
|
|
83739
|
+
function buildExitedLifecycleFact(auditArgs, emittedAt) {
|
|
83740
|
+
const { sessionId: _sessionId, machineId: _machineId, ...fields } = auditArgs;
|
|
83741
|
+
return {
|
|
83742
|
+
kind: "exited",
|
|
83743
|
+
...fields,
|
|
83744
|
+
revisionKey: buildAgentLifecycleRevisionKey("exited", {
|
|
83745
|
+
chatroomId: auditArgs.chatroomId,
|
|
83746
|
+
role: auditArgs.role,
|
|
83747
|
+
pid: auditArgs.pid,
|
|
83748
|
+
emittedAt
|
|
83749
|
+
}),
|
|
83750
|
+
emittedAt
|
|
83751
|
+
};
|
|
83752
|
+
}
|
|
83753
|
+
function normalizeAgentLifecycleFact(raw) {
|
|
83754
|
+
if (!raw || typeof raw !== "object") {
|
|
83755
|
+
throw new Error("Invalid agent lifecycle fact");
|
|
83756
|
+
}
|
|
83757
|
+
const value = raw;
|
|
83758
|
+
const { sessionId: _sessionId, machineId: _machineId, ...rest } = value;
|
|
83759
|
+
const kind = rest.kind;
|
|
83760
|
+
if (kind === "cleared_all_pids") {
|
|
83761
|
+
return {
|
|
83762
|
+
kind: "cleared_all_pids",
|
|
83763
|
+
revisionKey: String(rest.revisionKey),
|
|
83764
|
+
emittedAt: Number(rest.emittedAt)
|
|
83765
|
+
};
|
|
83766
|
+
}
|
|
83767
|
+
if (kind === "spawned" || kind === "exited") {
|
|
83768
|
+
return rest;
|
|
83769
|
+
}
|
|
83770
|
+
throw new Error(`Unknown agent lifecycle fact kind: ${String(kind)}`);
|
|
83771
|
+
}
|
|
83772
|
+
function agentLifecycleDeliveryKey(machineId, fact) {
|
|
83773
|
+
if (fact.kind === "cleared_all_pids")
|
|
83774
|
+
return `${machineId}:__machine__`;
|
|
83775
|
+
return `${machineId}:${fact.chatroomId}:${fact.role.toLowerCase()}`;
|
|
83776
|
+
}
|
|
83777
|
+
function buildAgentLifecycleRevisionKey(prefix, parts2) {
|
|
83778
|
+
return `${prefix}:${Object.entries(parts2).filter(([, v3]) => v3 !== undefined).map(([k, v3]) => `${k}=${v3}`).join(":")}`;
|
|
83779
|
+
}
|
|
83780
|
+
|
|
83781
|
+
// src/daemon/infrastructure/outbox/agent-lifecycle-outbox.ts
|
|
83782
|
+
function createAgentLifecycleOutboxRegistry(machineId, createSend, options) {
|
|
83783
|
+
const store = openDurableFifoQueueStore(resolveOutboxDbPath(machineId, "agent-lifecycle"));
|
|
83784
|
+
return createKeyedFifoBatchedOutboxRegistry({
|
|
83785
|
+
store,
|
|
83786
|
+
batchSize: AGENT_LIFECYCLE_OUTBOX_BATCH_SIZE,
|
|
83787
|
+
createSend: (key) => async (facts) => {
|
|
83788
|
+
const results = [];
|
|
83789
|
+
for (const fact of facts)
|
|
83790
|
+
results.push(await createSend(key)(fact));
|
|
83791
|
+
return results;
|
|
83792
|
+
},
|
|
83793
|
+
serialize: JSON.stringify,
|
|
83794
|
+
deserialize: (serialized) => normalizeAgentLifecycleFact(JSON.parse(serialized)),
|
|
83795
|
+
retryDelayMs: 500,
|
|
83796
|
+
maxRetryDelayMs: 5 * 60000,
|
|
83797
|
+
onError: options?.onError,
|
|
83798
|
+
classifyOutcome: () => ({ kind: "success" })
|
|
83799
|
+
});
|
|
83800
|
+
}
|
|
83801
|
+
function agentLifecycleKey(machineId, fact) {
|
|
83802
|
+
return agentLifecycleDeliveryKey(machineId, fact);
|
|
83803
|
+
}
|
|
83804
|
+
var AGENT_LIFECYCLE_OUTBOX_BATCH_SIZE = 1;
|
|
83805
|
+
var init_agent_lifecycle_outbox = __esm(() => {
|
|
83806
|
+
init_durable_fifo_queue_store();
|
|
83807
|
+
init_keyed_fifo_batched_outbox_registry();
|
|
83808
|
+
init_outbox_db_path();
|
|
83809
|
+
});
|
|
83810
|
+
|
|
83811
|
+
// src/daemon/infrastructure/outbox/agent-lifecycle-send.ts
|
|
83812
|
+
function toConvexLifecycleFact(fact) {
|
|
83813
|
+
const normalized = normalizeAgentLifecycleFact(fact);
|
|
83814
|
+
if (normalized.kind === "cleared_all_pids")
|
|
83815
|
+
return normalized;
|
|
83816
|
+
return {
|
|
83817
|
+
...normalized,
|
|
83818
|
+
chatroomId: normalized.chatroomId
|
|
83819
|
+
};
|
|
83820
|
+
}
|
|
83821
|
+
function createAgentLifecycleSend(session2) {
|
|
83822
|
+
return async (fact) => {
|
|
83823
|
+
const args2 = {
|
|
83824
|
+
sessionId: session2.sessionId,
|
|
83825
|
+
machineId: session2.machineId,
|
|
83826
|
+
fact: toConvexLifecycleFact(fact)
|
|
83827
|
+
};
|
|
83828
|
+
return await session2.backend.mutation(api.machines.projectAgentLifecycleFact, args2);
|
|
83829
|
+
};
|
|
83830
|
+
}
|
|
83831
|
+
var init_agent_lifecycle_send = __esm(() => {
|
|
83832
|
+
init_api3();
|
|
83833
|
+
});
|
|
83834
|
+
|
|
83835
|
+
// src/daemon/entry/agent-lifecycle-outbox-runtime.ts
|
|
83836
|
+
function createAgentLifecycleOutboxForSession(args2) {
|
|
83837
|
+
return createAgentLifecycleOutboxRegistry(args2.machineId, () => createAgentLifecycleSend({
|
|
83838
|
+
sessionId: args2.sessionId,
|
|
83839
|
+
machineId: args2.machineId,
|
|
83840
|
+
backend: args2.backend
|
|
83841
|
+
}));
|
|
83842
|
+
}
|
|
83843
|
+
function enqueueAgentLifecycleFact(registry2, machineId, fact) {
|
|
83844
|
+
return registry2.enqueue(agentLifecycleKey(machineId, fact), fact);
|
|
83845
|
+
}
|
|
83846
|
+
var init_agent_lifecycle_outbox_runtime = __esm(() => {
|
|
83847
|
+
init_agent_lifecycle_outbox();
|
|
83848
|
+
init_agent_lifecycle_send();
|
|
83849
|
+
});
|
|
83850
|
+
|
|
83518
83851
|
// src/daemon/entry/daemon-services.ts
|
|
83519
83852
|
function DaemonMutableStateServiceLive(init2) {
|
|
83520
83853
|
return exports_Layer.effect(DaemonMutableStateService, exports_Effect.gen(function* () {
|
|
@@ -83526,7 +83859,10 @@ function DaemonMutableStateServiceLive(init2) {
|
|
|
83526
83859
|
};
|
|
83527
83860
|
}));
|
|
83528
83861
|
}
|
|
83529
|
-
var
|
|
83862
|
+
var AgentLifecycleOutboxService, AgentLifecycleOutboxServiceLive = (registry2, machineId) => exports_Layer.succeed(AgentLifecycleOutboxService, {
|
|
83863
|
+
enqueue: (fact) => exports_Effect.promise(() => enqueueAgentLifecycleFact(registry2, machineId, fact)),
|
|
83864
|
+
stopAll: () => exports_Effect.promise(() => registry2.stopAll())
|
|
83865
|
+
}), DaemonMachineService, DaemonMachineServiceLive = (ops) => exports_Layer.succeed(DaemonMachineService, {
|
|
83530
83866
|
clearAgentPid: (machineId, chatroomId, role) => exports_Effect.promise(() => ops.clearAgentPid(machineId, chatroomId, role)),
|
|
83531
83867
|
persistAgentPid: (machineId, chatroomId, role, pid, harness) => exports_Effect.promise(() => ops.persistAgentPid(machineId, chatroomId, role, pid, harness)),
|
|
83532
83868
|
listAgentEntries: (machineId) => exports_Effect.promise(() => ops.listAgentEntries(machineId)),
|
|
@@ -83550,6 +83886,9 @@ var DaemonMachineService, DaemonMachineServiceLive = (ops) => exports_Layer.succ
|
|
|
83550
83886
|
}), DaemonSessionService, DaemonMutableStateService;
|
|
83551
83887
|
var init_daemon_services = __esm(() => {
|
|
83552
83888
|
init_esm();
|
|
83889
|
+
init_agent_lifecycle_outbox_runtime();
|
|
83890
|
+
AgentLifecycleOutboxService = class AgentLifecycleOutboxService extends exports_Context.Tag("AgentLifecycleOutboxService")() {
|
|
83891
|
+
};
|
|
83553
83892
|
DaemonMachineService = class DaemonMachineService extends exports_Context.Tag("DaemonMachineService")() {
|
|
83554
83893
|
};
|
|
83555
83894
|
DaemonSpawningService = class DaemonSpawningService extends exports_Context.Tag("DaemonSpawningService")() {
|
|
@@ -83572,7 +83911,7 @@ function daemonSessionToLayers(init2) {
|
|
|
83572
83911
|
return exports_Layer.mergeAll(BackendServiceLive({
|
|
83573
83912
|
mutation: (e, a) => init2.backend.mutation(e, a),
|
|
83574
83913
|
query: (e, a) => init2.backend.query(e, a)
|
|
83575
|
-
}), ProcessServiceLive, ClockServiceLive, FsServiceLive, DaemonMachineServiceLive(init2.machine), DaemonSpawningServiceLive(init2.spawning), DaemonAgentProcessManagerServiceLive(init2.agentProcessManager), DaemonMutableStateServiceLive({
|
|
83914
|
+
}), ProcessServiceLive, ClockServiceLive, FsServiceLive, DaemonMachineServiceLive(init2.machine), AgentLifecycleOutboxServiceLive(init2.agentLifecycleOutbox, init2.machineId), DaemonSpawningServiceLive(init2.spawning), DaemonAgentProcessManagerServiceLive(init2.agentProcessManager), DaemonMutableStateServiceLive({
|
|
83576
83915
|
lastPushedGitState: init2.lastPushedGitState,
|
|
83577
83916
|
lastPushedModels: init2.lastPushedModels,
|
|
83578
83917
|
lastPushedHarnessFingerprint: init2.lastPushedHarnessFingerprint,
|
|
@@ -83696,10 +84035,18 @@ var init_register_listeners = __esm(() => {
|
|
|
83696
84035
|
|
|
83697
84036
|
// src/daemon/entry/handlers/daemon-restart-cleanup.ts
|
|
83698
84037
|
var clearStaleSpawnedPidsEffect = () => exports_Effect.gen(function* () {
|
|
83699
|
-
const
|
|
84038
|
+
const outbox = yield* AgentLifecycleOutboxService;
|
|
83700
84039
|
const session2 = yield* DaemonSessionService;
|
|
83701
|
-
const
|
|
83702
|
-
|
|
84040
|
+
const emittedAt = Date.now();
|
|
84041
|
+
const result = yield* outbox.enqueue({
|
|
84042
|
+
kind: "cleared_all_pids",
|
|
84043
|
+
revisionKey: buildAgentLifecycleRevisionKey("cleared_all", {
|
|
84044
|
+
machineId: session2.machineId,
|
|
84045
|
+
emittedAt
|
|
84046
|
+
}),
|
|
84047
|
+
emittedAt
|
|
84048
|
+
});
|
|
84049
|
+
return result.clearedCount ?? 0;
|
|
83703
84050
|
}), reapOrphanCommandRunsEffect = () => exports_Effect.gen(function* () {
|
|
83704
84051
|
const backend2 = yield* BackendService;
|
|
83705
84052
|
const session2 = yield* DaemonSessionService;
|
|
@@ -83737,26 +84084,26 @@ import { createHash as createHash2 } from "node:crypto";
|
|
|
83737
84084
|
import {
|
|
83738
84085
|
appendFileSync,
|
|
83739
84086
|
existsSync as existsSync6,
|
|
83740
|
-
mkdirSync as
|
|
84087
|
+
mkdirSync as mkdirSync5,
|
|
83741
84088
|
readFileSync as readFileSync8,
|
|
83742
84089
|
renameSync,
|
|
83743
84090
|
unlinkSync,
|
|
83744
84091
|
writeFileSync as writeFileSync3
|
|
83745
84092
|
} from "node:fs";
|
|
83746
|
-
import { homedir as
|
|
83747
|
-
import { join as
|
|
84093
|
+
import { homedir as homedir6 } from "node:os";
|
|
84094
|
+
import { join as join18 } from "node:path";
|
|
83748
84095
|
function getUrlHash() {
|
|
83749
84096
|
const url2 = getConvexUrl();
|
|
83750
84097
|
return createHash2("sha256").update(url2).digest("hex").substring(0, 8);
|
|
83751
84098
|
}
|
|
83752
84099
|
function getChildPidsFilePath() {
|
|
83753
|
-
const dir =
|
|
83754
|
-
return
|
|
84100
|
+
const dir = join18(homedir6(), ".chatroom");
|
|
84101
|
+
return join18(dir, `daemon-children-${getUrlHash()}.pids`);
|
|
83755
84102
|
}
|
|
83756
84103
|
function ensureChatroomDir2() {
|
|
83757
|
-
const dir =
|
|
84104
|
+
const dir = join18(homedir6(), ".chatroom");
|
|
83758
84105
|
if (!existsSync6(dir)) {
|
|
83759
|
-
|
|
84106
|
+
mkdirSync5(dir, { recursive: true, mode: 448 });
|
|
83760
84107
|
}
|
|
83761
84108
|
}
|
|
83762
84109
|
function readPids() {
|
|
@@ -83869,7 +84216,7 @@ var init_orphan_tracker = __esm(() => {
|
|
|
83869
84216
|
// src/daemon/entry/handlers/process/output-store.ts
|
|
83870
84217
|
import { appendFile as appendFile2, mkdir as mkdir8, readFile as readFile6, rm as rm2 } from "node:fs/promises";
|
|
83871
84218
|
import { tmpdir } from "node:os";
|
|
83872
|
-
import { join as
|
|
84219
|
+
import { join as join19 } from "node:path";
|
|
83873
84220
|
|
|
83874
84221
|
class TempFileOutputStore {
|
|
83875
84222
|
state;
|
|
@@ -83932,7 +84279,7 @@ function createOutputStore(runId) {
|
|
|
83932
84279
|
if (!RUN_ID_RE.test(runId)) {
|
|
83933
84280
|
throw new Error(`Invalid runId: ${runId}`);
|
|
83934
84281
|
}
|
|
83935
|
-
const filePath =
|
|
84282
|
+
const filePath = join19(TEMP_DIR, `${runId}.log`);
|
|
83936
84283
|
return new TempFileOutputStore(filePath);
|
|
83937
84284
|
}
|
|
83938
84285
|
async function ensureTempDir() {
|
|
@@ -83946,7 +84293,7 @@ async function cleanOrphanTempFiles() {
|
|
|
83946
84293
|
var TAIL_WINDOW_BYTES, TEMP_DIR, RUN_ID_RE, MAX_TAIL_LINES_V2 = 50;
|
|
83947
84294
|
var init_output_store = __esm(() => {
|
|
83948
84295
|
TAIL_WINDOW_BYTES = 32 * 1024;
|
|
83949
|
-
TEMP_DIR =
|
|
84296
|
+
TEMP_DIR = join19(tmpdir(), "chatroom-cli", "runs");
|
|
83950
84297
|
RUN_ID_RE = /^[a-z0-9]+$/i;
|
|
83951
84298
|
});
|
|
83952
84299
|
|
|
@@ -84014,74 +84361,6 @@ async function logDaemonAuditEvent(logEvent, event) {
|
|
|
84014
84361
|
});
|
|
84015
84362
|
}
|
|
84016
84363
|
|
|
84017
|
-
// src/daemon/infrastructure/inbox/task-snapshot-state.ts
|
|
84018
|
-
function snapshotKey(taskId, role) {
|
|
84019
|
-
return `${taskId}:${role.toLowerCase()}`;
|
|
84020
|
-
}
|
|
84021
|
-
|
|
84022
|
-
class MachineTaskSnapshotState {
|
|
84023
|
-
snapshots = new Map;
|
|
84024
|
-
replace(snapshots) {
|
|
84025
|
-
this.snapshots.clear();
|
|
84026
|
-
this.upsert(snapshots);
|
|
84027
|
-
}
|
|
84028
|
-
applySignalPage(signals, snapshots) {
|
|
84029
|
-
const snapshotsByKey = new Map(snapshots.map((snapshot) => [
|
|
84030
|
-
snapshotKey(snapshot.taskId, snapshot.agentConfig.role),
|
|
84031
|
-
snapshot
|
|
84032
|
-
]));
|
|
84033
|
-
for (const signal of signals) {
|
|
84034
|
-
const key = snapshotKey(signal.taskId, signal.targetRole);
|
|
84035
|
-
const snapshot = snapshotsByKey.get(key);
|
|
84036
|
-
if (snapshot) {
|
|
84037
|
-
this.snapshots.set(key, snapshot);
|
|
84038
|
-
} else {
|
|
84039
|
-
this.snapshots.delete(key);
|
|
84040
|
-
}
|
|
84041
|
-
}
|
|
84042
|
-
}
|
|
84043
|
-
listForRole(chatroomId, role) {
|
|
84044
|
-
const roleLower = role.toLowerCase();
|
|
84045
|
-
return [...this.snapshots.values()].filter((snapshot) => snapshot.chatroomId === chatroomId && snapshot.agentConfig.role.toLowerCase() === roleLower);
|
|
84046
|
-
}
|
|
84047
|
-
listAll() {
|
|
84048
|
-
return [...this.snapshots.values()];
|
|
84049
|
-
}
|
|
84050
|
-
setDesiredState(chatroomId, role, desiredState) {
|
|
84051
|
-
const roleLower = role.toLowerCase();
|
|
84052
|
-
for (const [key, snapshot] of this.snapshots) {
|
|
84053
|
-
if (snapshot.chatroomId !== chatroomId || snapshot.agentConfig.role.toLowerCase() !== roleLower) {
|
|
84054
|
-
continue;
|
|
84055
|
-
}
|
|
84056
|
-
this.snapshots.set(key, {
|
|
84057
|
-
...snapshot,
|
|
84058
|
-
agentConfig: { ...snapshot.agentConfig, desiredState }
|
|
84059
|
-
});
|
|
84060
|
-
}
|
|
84061
|
-
}
|
|
84062
|
-
upsert(snapshots) {
|
|
84063
|
-
for (const snapshot of snapshots) {
|
|
84064
|
-
this.snapshots.set(snapshotKey(snapshot.taskId, snapshot.agentConfig.role), snapshot);
|
|
84065
|
-
}
|
|
84066
|
-
}
|
|
84067
|
-
}
|
|
84068
|
-
|
|
84069
|
-
// src/daemon/entry/native-delivery/native-delivery-session-registry.ts
|
|
84070
|
-
function registerNativeDeliverySession(ctx) {
|
|
84071
|
-
registered = {
|
|
84072
|
-
...ctx,
|
|
84073
|
-
taskSnapshotState: ctx.taskSnapshotState ?? new MachineTaskSnapshotState
|
|
84074
|
-
};
|
|
84075
|
-
}
|
|
84076
|
-
function unregisterNativeDeliverySession() {
|
|
84077
|
-
registered = null;
|
|
84078
|
-
}
|
|
84079
|
-
function getNativeDeliverySession() {
|
|
84080
|
-
return registered;
|
|
84081
|
-
}
|
|
84082
|
-
var registered = null;
|
|
84083
|
-
var init_native_delivery_session_registry = () => {};
|
|
84084
|
-
|
|
84085
84364
|
// ../../services/backend/config/reliability.ts
|
|
84086
84365
|
var HARNESS_SESSION_READY_TIMEOUT_MS = 5000, DAEMON_HEARTBEAT_INTERVAL_MS, DAEMON_HEARTBEAT_TTL_MS, AGENT_REQUEST_DEADLINE_MS = 120000, OBSERVED_FULL_PUSH_INTERVAL_MS, OBSERVED_SYNC_RECONCILE_MS, WORKSPACE_RECENCY_WINDOW_MS, WORKSPACE_LIST_RECONCILE_MS, CONNECTION_CLOSE_REQUEST_TTL_MS, ENHANCER_TERMINAL_JOB_RETENTION_MS;
|
|
84087
84366
|
var init_reliability = __esm(() => {
|
|
@@ -98811,8 +99090,6 @@ var init_assigned_task_snapshot_contract = __esm(() => {
|
|
|
98811
99090
|
assignedTo: exports_external.string().optional(),
|
|
98812
99091
|
lastSeenAction: exports_external.string().nullable().optional(),
|
|
98813
99092
|
lastStatus: exports_external.string().nullable().optional(),
|
|
98814
|
-
spawnedAgentPid: exports_external.number().optional(),
|
|
98815
|
-
desiredState: agentDesiredStateSchema.optional(),
|
|
98816
99093
|
sessionAugmentation: sessionAugmentationSchema.optional()
|
|
98817
99094
|
};
|
|
98818
99095
|
assignedTaskSignalSchema = exports_external.object(assignedTaskSignalBootstrapFields);
|
|
@@ -98889,13 +99166,99 @@ function getNativeDeliveryLedger() {
|
|
|
98889
99166
|
}
|
|
98890
99167
|
var sharedLedger;
|
|
98891
99168
|
|
|
99169
|
+
// src/daemon/infrastructure/agent-operational/agent-operational-read-model.ts
|
|
99170
|
+
function isOperationalDesiredRunning(row) {
|
|
99171
|
+
return row?.operationalState === "running" || row?.operationalState === "starting";
|
|
99172
|
+
}
|
|
99173
|
+
|
|
99174
|
+
class AgentOperationalReadModel {
|
|
99175
|
+
rows = new Map;
|
|
99176
|
+
replace(rows) {
|
|
99177
|
+
const changed = [];
|
|
99178
|
+
const nextKeys = new Set;
|
|
99179
|
+
for (const row of rows) {
|
|
99180
|
+
const key = roleKey(row.chatroomId, row.role);
|
|
99181
|
+
nextKeys.add(key);
|
|
99182
|
+
const prev = this.rows.get(key);
|
|
99183
|
+
if (!prev || prev.revisionKey !== row.revisionKey)
|
|
99184
|
+
changed.push({ chatroomId: row.chatroomId, role: row.role });
|
|
99185
|
+
this.rows.set(key, row);
|
|
99186
|
+
}
|
|
99187
|
+
for (const [key, prev] of this.rows) {
|
|
99188
|
+
if (!nextKeys.has(key)) {
|
|
99189
|
+
changed.push({ chatroomId: prev.chatroomId, role: prev.role });
|
|
99190
|
+
this.rows.delete(key);
|
|
99191
|
+
}
|
|
99192
|
+
}
|
|
99193
|
+
return changed;
|
|
99194
|
+
}
|
|
99195
|
+
get(chatroomId, role) {
|
|
99196
|
+
return this.rows.get(roleKey(chatroomId, role));
|
|
99197
|
+
}
|
|
99198
|
+
}
|
|
99199
|
+
var roleKey = (chatroomId, role) => `${chatroomId}:${role.toLowerCase()}`;
|
|
99200
|
+
|
|
99201
|
+
// src/daemon/infrastructure/inbox/task-snapshot-state.ts
|
|
99202
|
+
function snapshotKey(taskId, role) {
|
|
99203
|
+
return `${taskId}:${role.toLowerCase()}`;
|
|
99204
|
+
}
|
|
99205
|
+
|
|
99206
|
+
class MachineTaskSnapshotState {
|
|
99207
|
+
snapshots = new Map;
|
|
99208
|
+
replace(snapshots) {
|
|
99209
|
+
this.snapshots.clear();
|
|
99210
|
+
this.upsert(snapshots);
|
|
99211
|
+
}
|
|
99212
|
+
applySignalPage(signals, snapshots) {
|
|
99213
|
+
const snapshotsByKey = new Map(snapshots.map((snapshot) => [
|
|
99214
|
+
snapshotKey(snapshot.taskId, snapshot.agentConfig.role),
|
|
99215
|
+
snapshot
|
|
99216
|
+
]));
|
|
99217
|
+
for (const signal of signals) {
|
|
99218
|
+
const key = snapshotKey(signal.taskId, signal.targetRole);
|
|
99219
|
+
const snapshot = snapshotsByKey.get(key);
|
|
99220
|
+
if (snapshot) {
|
|
99221
|
+
this.snapshots.set(key, snapshot);
|
|
99222
|
+
} else {
|
|
99223
|
+
this.snapshots.delete(key);
|
|
99224
|
+
}
|
|
99225
|
+
}
|
|
99226
|
+
}
|
|
99227
|
+
listForRole(chatroomId, role) {
|
|
99228
|
+
const roleLower = role.toLowerCase();
|
|
99229
|
+
return [...this.snapshots.values()].filter((snapshot) => snapshot.chatroomId === chatroomId && snapshot.agentConfig.role.toLowerCase() === roleLower);
|
|
99230
|
+
}
|
|
99231
|
+
listAll() {
|
|
99232
|
+
return [...this.snapshots.values()];
|
|
99233
|
+
}
|
|
99234
|
+
upsert(snapshots) {
|
|
99235
|
+
for (const snapshot of snapshots) {
|
|
99236
|
+
this.snapshots.set(snapshotKey(snapshot.taskId, snapshot.agentConfig.role), snapshot);
|
|
99237
|
+
}
|
|
99238
|
+
}
|
|
99239
|
+
}
|
|
99240
|
+
|
|
99241
|
+
// src/daemon/entry/native-delivery/native-delivery-session-registry.ts
|
|
99242
|
+
function registerNativeDeliverySession(ctx) {
|
|
99243
|
+
registered = {
|
|
99244
|
+
...ctx,
|
|
99245
|
+
taskSnapshotState: ctx.taskSnapshotState ?? new MachineTaskSnapshotState,
|
|
99246
|
+
agentOperationalReadModel: ctx.agentOperationalReadModel ?? new AgentOperationalReadModel
|
|
99247
|
+
};
|
|
99248
|
+
}
|
|
99249
|
+
function unregisterNativeDeliverySession() {
|
|
99250
|
+
registered = null;
|
|
99251
|
+
}
|
|
99252
|
+
function getNativeDeliverySession() {
|
|
99253
|
+
return registered;
|
|
99254
|
+
}
|
|
99255
|
+
var registered = null;
|
|
99256
|
+
var init_native_delivery_session_registry = () => {};
|
|
99257
|
+
|
|
98892
99258
|
// src/daemon/domain/entities/assigned-task.ts
|
|
98893
99259
|
function isDeliverableTaskStatus(status3) {
|
|
98894
99260
|
return status3 === "pending" || status3 === "acknowledged";
|
|
98895
99261
|
}
|
|
98896
|
-
function isAgentDesiredRunning(desiredState) {
|
|
98897
|
-
return desiredState === "running";
|
|
98898
|
-
}
|
|
98899
99262
|
var init_assigned_task = () => {};
|
|
98900
99263
|
|
|
98901
99264
|
// src/daemon/domain/usecase/check-agent-slot.ts
|
|
@@ -98925,8 +99288,9 @@ function explainAgentReadyForNativeDeliveryBlock(task, slot) {
|
|
|
98925
99288
|
if (!isNativeHarness(agentConfig.agentHarness)) {
|
|
98926
99289
|
return `not_native_harness (harness=${agentConfig.agentHarness})`;
|
|
98927
99290
|
}
|
|
98928
|
-
|
|
98929
|
-
|
|
99291
|
+
const operational = getNativeDeliverySession()?.agentOperationalReadModel?.get(task.chatroomId, agentConfig.role);
|
|
99292
|
+
if (!isOperationalDesiredRunning(operational)) {
|
|
99293
|
+
return `operational_state_not_running (state=${operational?.operationalState ?? "missing"})`;
|
|
98930
99294
|
}
|
|
98931
99295
|
if (!slot) {
|
|
98932
99296
|
return agentConfig.spawnedAgentPid == null ? "spawned_pid_missing" : `slot_missing (expectedPid=${agentConfig.spawnedAgentPid})`;
|
|
@@ -98954,6 +99318,7 @@ function isDeliverableNativeTaskStatus(status3) {
|
|
|
98954
99318
|
}
|
|
98955
99319
|
var init_native_ready_invariant = __esm(() => {
|
|
98956
99320
|
init_types();
|
|
99321
|
+
init_native_delivery_session_registry();
|
|
98957
99322
|
init_assigned_task();
|
|
98958
99323
|
init_check_agent_slot();
|
|
98959
99324
|
});
|
|
@@ -99466,20 +99831,20 @@ function mapAssignedTaskSnapshotList(rows) {
|
|
|
99466
99831
|
}
|
|
99467
99832
|
|
|
99468
99833
|
// src/daemon/entry/restart-orchestrator-in-flight.ts
|
|
99469
|
-
function
|
|
99834
|
+
function roleKey2(chatroomId, role) {
|
|
99470
99835
|
return `${chatroomId}:${role.toLowerCase()}`;
|
|
99471
99836
|
}
|
|
99472
99837
|
function markRestartOrchestratorInFlight(chatroomId, role, correlationId) {
|
|
99473
|
-
inFlight.set(
|
|
99838
|
+
inFlight.set(roleKey2(chatroomId, role), correlationId);
|
|
99474
99839
|
}
|
|
99475
99840
|
function clearRestartOrchestratorInFlight(chatroomId, role, correlationId) {
|
|
99476
|
-
const key =
|
|
99841
|
+
const key = roleKey2(chatroomId, role);
|
|
99477
99842
|
if (correlationId !== undefined && inFlight.get(key) !== correlationId)
|
|
99478
99843
|
return;
|
|
99479
99844
|
inFlight.delete(key);
|
|
99480
99845
|
}
|
|
99481
99846
|
function isRestartOrchestratorInFlight(chatroomId, role) {
|
|
99482
|
-
return inFlight.has(
|
|
99847
|
+
return inFlight.has(roleKey2(chatroomId, role));
|
|
99483
99848
|
}
|
|
99484
99849
|
function filterSnapshotsExcludingRestartInFlight(snapshots) {
|
|
99485
99850
|
return snapshots.filter((row) => !isRestartOrchestratorInFlight(row.chatroomId, row.agentConfig.role));
|
|
@@ -99490,7 +99855,7 @@ var init_restart_orchestrator_in_flight = __esm(() => {
|
|
|
99490
99855
|
});
|
|
99491
99856
|
|
|
99492
99857
|
// src/daemon/entry/role-delivery-state.ts
|
|
99493
|
-
function
|
|
99858
|
+
function roleKey3(chatroomId, role) {
|
|
99494
99859
|
return `${chatroomId}:${role.toLowerCase()}`;
|
|
99495
99860
|
}
|
|
99496
99861
|
|
|
@@ -99499,10 +99864,10 @@ class RoleDeliveryState {
|
|
|
99499
99864
|
inFlight = new Set;
|
|
99500
99865
|
nativeNudgeFailures = new Map;
|
|
99501
99866
|
getGeneration(chatroomId, role) {
|
|
99502
|
-
return this.generation.get(
|
|
99867
|
+
return this.generation.get(roleKey3(chatroomId, role)) ?? 0;
|
|
99503
99868
|
}
|
|
99504
99869
|
resetDeliveryState(chatroomId, role) {
|
|
99505
|
-
const key =
|
|
99870
|
+
const key = roleKey3(chatroomId, role);
|
|
99506
99871
|
const next4 = (this.generation.get(key) ?? 0) + 1;
|
|
99507
99872
|
this.generation.set(key, next4);
|
|
99508
99873
|
this.inFlight.delete(key);
|
|
@@ -99510,26 +99875,26 @@ class RoleDeliveryState {
|
|
|
99510
99875
|
return next4;
|
|
99511
99876
|
}
|
|
99512
99877
|
tryAcquireDelivery(chatroomId, role) {
|
|
99513
|
-
const key =
|
|
99878
|
+
const key = roleKey3(chatroomId, role);
|
|
99514
99879
|
if (this.inFlight.has(key))
|
|
99515
99880
|
return false;
|
|
99516
99881
|
this.inFlight.add(key);
|
|
99517
99882
|
return true;
|
|
99518
99883
|
}
|
|
99519
99884
|
releaseDelivery(chatroomId, role) {
|
|
99520
|
-
this.inFlight.delete(
|
|
99885
|
+
this.inFlight.delete(roleKey3(chatroomId, role));
|
|
99521
99886
|
}
|
|
99522
99887
|
recordNativeNudgeFailure(chatroomId, role) {
|
|
99523
|
-
const key =
|
|
99888
|
+
const key = roleKey3(chatroomId, role);
|
|
99524
99889
|
const count3 = (this.nativeNudgeFailures.get(key) ?? 0) + 1;
|
|
99525
99890
|
this.nativeNudgeFailures.set(key, count3);
|
|
99526
99891
|
return count3;
|
|
99527
99892
|
}
|
|
99528
99893
|
clearNativeNudgeFailures(chatroomId, role) {
|
|
99529
|
-
this.nativeNudgeFailures.delete(
|
|
99894
|
+
this.nativeNudgeFailures.delete(roleKey3(chatroomId, role));
|
|
99530
99895
|
}
|
|
99531
99896
|
getNativeNudgeFailures(chatroomId, role) {
|
|
99532
|
-
return this.nativeNudgeFailures.get(
|
|
99897
|
+
return this.nativeNudgeFailures.get(roleKey3(chatroomId, role)) ?? 0;
|
|
99533
99898
|
}
|
|
99534
99899
|
}
|
|
99535
99900
|
function getRoleDeliveryState() {
|
|
@@ -99916,8 +100281,6 @@ function createStartAgentDeps(agentMgr, session2) {
|
|
|
99916
100281
|
return {
|
|
99917
100282
|
agentProcessManager: {
|
|
99918
100283
|
ensureRunning: async (args2) => {
|
|
99919
|
-
const taskSnapshotState = getNativeDeliverySession()?.taskSnapshotState;
|
|
99920
|
-
taskSnapshotState?.setDesiredState(args2.chatroomId, args2.role, "running");
|
|
99921
100284
|
const result = await exports_Effect.runPromise(agentMgr.ensureRunning({
|
|
99922
100285
|
chatroomId: args2.chatroomId,
|
|
99923
100286
|
role: args2.role,
|
|
@@ -99927,9 +100290,7 @@ function createStartAgentDeps(agentMgr, session2) {
|
|
|
99927
100290
|
reason: args2.reason,
|
|
99928
100291
|
wantResume: args2.wantResume
|
|
99929
100292
|
}));
|
|
99930
|
-
if (!result.success) {
|
|
99931
|
-
taskSnapshotState?.setDesiredState(args2.chatroomId, args2.role, "stopped");
|
|
99932
|
-
}
|
|
100293
|
+
if (!result.success) {}
|
|
99933
100294
|
return result;
|
|
99934
100295
|
}
|
|
99935
100296
|
},
|
|
@@ -100052,7 +100413,6 @@ function createRecoverAgentStateDeps(agentMgr, session2) {
|
|
|
100052
100413
|
var init_agent_control_bridge = __esm(() => {
|
|
100053
100414
|
init_esm();
|
|
100054
100415
|
init_api3();
|
|
100055
|
-
init_native_delivery_session_registry();
|
|
100056
100416
|
init_restart_orchestrator();
|
|
100057
100417
|
});
|
|
100058
100418
|
|
|
@@ -100188,9 +100548,9 @@ var init_daemon_process_scan = __esm(() => {
|
|
|
100188
100548
|
|
|
100189
100549
|
// src/commands/machine/pid.ts
|
|
100190
100550
|
import { createHash as createHash3 } from "node:crypto";
|
|
100191
|
-
import { existsSync as existsSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync4, unlinkSync as unlinkSync2, mkdirSync as
|
|
100192
|
-
import { homedir as
|
|
100193
|
-
import { join as
|
|
100551
|
+
import { existsSync as existsSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync4, unlinkSync as unlinkSync2, mkdirSync as mkdirSync6 } from "node:fs";
|
|
100552
|
+
import { homedir as homedir7 } from "node:os";
|
|
100553
|
+
import { join as join20 } from "node:path";
|
|
100194
100554
|
function getUrlHash2() {
|
|
100195
100555
|
const url3 = getConvexUrl();
|
|
100196
100556
|
return createHash3("sha256").update(url3).digest("hex").substring(0, 8);
|
|
@@ -100200,11 +100560,11 @@ function getPidFileName() {
|
|
|
100200
100560
|
}
|
|
100201
100561
|
function ensureChatroomDir3() {
|
|
100202
100562
|
if (!existsSync8(CHATROOM_DIR4)) {
|
|
100203
|
-
|
|
100563
|
+
mkdirSync6(CHATROOM_DIR4, { recursive: true, mode: 448 });
|
|
100204
100564
|
}
|
|
100205
100565
|
}
|
|
100206
100566
|
function getPidFilePath() {
|
|
100207
|
-
return
|
|
100567
|
+
return join20(CHATROOM_DIR4, getPidFileName());
|
|
100208
100568
|
}
|
|
100209
100569
|
function isProcessRunning(pid) {
|
|
100210
100570
|
try {
|
|
@@ -100350,7 +100710,7 @@ var CHATROOM_DIR4, LOCK_RETRY_INTERVAL_MS = 500, LOCK_RETRY_MAX_WAIT_MS = 15000,
|
|
|
100350
100710
|
var init_pid = __esm(() => {
|
|
100351
100711
|
init_daemon_process_scan();
|
|
100352
100712
|
init_client2();
|
|
100353
|
-
CHATROOM_DIR4 =
|
|
100713
|
+
CHATROOM_DIR4 = join20(homedir7(), ".chatroom");
|
|
100354
100714
|
});
|
|
100355
100715
|
|
|
100356
100716
|
// src/infrastructure/machine/crash-loop-tracker.ts
|
|
@@ -102096,9 +102456,8 @@ class AgentProcessManager {
|
|
|
102096
102456
|
console.log(` ⚠️ ${failureLog}: ${err.message}`);
|
|
102097
102457
|
this.queueExitRetry({ role, args: exitArgs });
|
|
102098
102458
|
});
|
|
102099
|
-
this.deps.
|
|
102100
|
-
|
|
102101
|
-
});
|
|
102459
|
+
const emittedAt = this.deps.clock.now();
|
|
102460
|
+
this.deps.lifecycleOutbox.enqueue(buildExitedLifecycleFact(exitArgs, emittedAt)).catch((err) => console.log(` ⚠️ Failed to enqueue agent exited lifecycle fact: ${err.message}`));
|
|
102102
102461
|
}
|
|
102103
102462
|
async clearAgentPidQuietly(chatroomId, role) {
|
|
102104
102463
|
try {
|
|
@@ -102502,28 +102861,23 @@ class AgentProcessManager {
|
|
|
102502
102861
|
}).catch((err) => {
|
|
102503
102862
|
console.log(` ⚠️ Failed to record agent.started event: ${err.message}`);
|
|
102504
102863
|
});
|
|
102505
|
-
this.deps.
|
|
102506
|
-
|
|
102507
|
-
|
|
102864
|
+
const emittedAt = this.deps.clock.now();
|
|
102865
|
+
this.deps.lifecycleOutbox.enqueue({
|
|
102866
|
+
kind: "spawned",
|
|
102508
102867
|
chatroomId: opts.chatroomId,
|
|
102509
102868
|
role: opts.role,
|
|
102510
102869
|
pid,
|
|
102511
102870
|
model: opts.model,
|
|
102512
102871
|
reason: opts.reason,
|
|
102513
|
-
...spawnResult.harnessSessionId ? { harnessSessionId: spawnResult.harnessSessionId } : {}
|
|
102514
|
-
|
|
102515
|
-
|
|
102516
|
-
|
|
102517
|
-
|
|
102518
|
-
|
|
102519
|
-
|
|
102520
|
-
|
|
102521
|
-
|
|
102522
|
-
pid,
|
|
102523
|
-
model: opts.model
|
|
102524
|
-
}).catch((err) => {
|
|
102525
|
-
console.log(` ⚠️ Failed to update PID in backend: ${err.message}`);
|
|
102526
|
-
});
|
|
102872
|
+
...spawnResult.harnessSessionId ? { harnessSessionId: spawnResult.harnessSessionId } : {},
|
|
102873
|
+
revisionKey: buildAgentLifecycleRevisionKey("spawned", {
|
|
102874
|
+
chatroomId: opts.chatroomId,
|
|
102875
|
+
role: opts.role,
|
|
102876
|
+
pid,
|
|
102877
|
+
emittedAt
|
|
102878
|
+
}),
|
|
102879
|
+
emittedAt
|
|
102880
|
+
}).catch((err) => console.log(` ⚠️ Failed to enqueue agent spawned lifecycle fact: ${err.message}`));
|
|
102527
102881
|
}
|
|
102528
102882
|
registerSpawnCallbacks(slot, opts, spawnResult, pid) {
|
|
102529
102883
|
if (spawnResult.onLogLine) {
|
|
@@ -102878,6 +103232,11 @@ function assembleDaemonSessionInit(args2) {
|
|
|
102878
103232
|
} = args2;
|
|
102879
103233
|
deps.backend.mutation = (endpoint, args3) => client4.mutation(endpoint, args3);
|
|
102880
103234
|
deps.backend.query = (endpoint, args3) => client4.query(endpoint, args3);
|
|
103235
|
+
const agentLifecycleOutbox = createAgentLifecycleOutboxForSession({
|
|
103236
|
+
sessionId: typedSessionId,
|
|
103237
|
+
machineId,
|
|
103238
|
+
backend: deps.backend
|
|
103239
|
+
});
|
|
102881
103240
|
deps.agentProcessManager = new AgentProcessManager({
|
|
102882
103241
|
logEvent: activeLogEvent ?? (async () => {
|
|
102883
103242
|
return;
|
|
@@ -102893,7 +103252,8 @@ function assembleDaemonSessionInit(args2) {
|
|
|
102893
103252
|
persistence: deps.machine,
|
|
102894
103253
|
spawning: deps.spawning,
|
|
102895
103254
|
crashLoop: new CrashLoopTracker,
|
|
102896
|
-
convexUrl
|
|
103255
|
+
convexUrl,
|
|
103256
|
+
lifecycleOutbox: { enqueue: (fact) => enqueueAgentLifecycleFact(agentLifecycleOutbox, machineId, fact) }
|
|
102897
103257
|
});
|
|
102898
103258
|
return {
|
|
102899
103259
|
client: client4,
|
|
@@ -102906,6 +103266,7 @@ function assembleDaemonSessionInit(args2) {
|
|
|
102906
103266
|
machine: deps.machine,
|
|
102907
103267
|
spawning: deps.spawning,
|
|
102908
103268
|
agentProcessManager: deps.agentProcessManager,
|
|
103269
|
+
agentLifecycleOutbox,
|
|
102909
103270
|
events: new DaemonEventBus,
|
|
102910
103271
|
agentServices,
|
|
102911
103272
|
lastPushedGitState: new Map,
|
|
@@ -103138,6 +103499,8 @@ var init_init_daemon = __esm(() => {
|
|
|
103138
103499
|
init_daemon_startup_log();
|
|
103139
103500
|
init_orphan_tracker();
|
|
103140
103501
|
init_output_store();
|
|
103502
|
+
init_agent_lifecycle_outbox_runtime();
|
|
103503
|
+
init_agent_lifecycle_outbox_runtime();
|
|
103141
103504
|
init_state_recovery();
|
|
103142
103505
|
init_pid();
|
|
103143
103506
|
init_storage();
|
|
@@ -105768,6 +106131,14 @@ var init_workspace_cache = __esm(() => {
|
|
|
105768
106131
|
|
|
105769
106132
|
// src/daemon/infrastructure/git/run-command.ts
|
|
105770
106133
|
import { spawn as spawn4 } from "node:child_process";
|
|
106134
|
+
function enqueueGit(cwd, task) {
|
|
106135
|
+
const tail = gitQueues.get(cwd) ?? Promise.resolve();
|
|
106136
|
+
const run3 = tail.then(task, task);
|
|
106137
|
+
gitQueues.set(cwd, run3.catch(() => {
|
|
106138
|
+
return;
|
|
106139
|
+
}));
|
|
106140
|
+
return run3;
|
|
106141
|
+
}
|
|
105771
106142
|
function runCommandSpawn(command, args2, cwd, options) {
|
|
105772
106143
|
const successExitCodes = options?.successExitCodes ?? [0];
|
|
105773
106144
|
return new Promise((resolve4) => {
|
|
@@ -105813,7 +106184,7 @@ function runCommandSpawn(command, args2, cwd, options) {
|
|
|
105813
106184
|
});
|
|
105814
106185
|
}
|
|
105815
106186
|
function runGit(args2, cwd, options) {
|
|
105816
|
-
return runCommandSpawn("git", args2, cwd, options);
|
|
106187
|
+
return enqueueGit(cwd, () => runCommandSpawn("git", options?.readOnly ? ["--no-optional-locks", ...args2] : args2, cwd, options));
|
|
105817
106188
|
}
|
|
105818
106189
|
function runGh(args2, cwd, options) {
|
|
105819
106190
|
return runCommandSpawn("gh", args2, cwd, {
|
|
@@ -105821,7 +106192,7 @@ function runGh(args2, cwd, options) {
|
|
|
105821
106192
|
env: { ...process.env, NO_COLOR: "1" }
|
|
105822
106193
|
});
|
|
105823
106194
|
}
|
|
105824
|
-
var DEFAULT_GIT_ENV;
|
|
106195
|
+
var DEFAULT_GIT_ENV, gitQueues;
|
|
105825
106196
|
var init_run_command = __esm(() => {
|
|
105826
106197
|
DEFAULT_GIT_ENV = {
|
|
105827
106198
|
...process.env,
|
|
@@ -105829,6 +106200,7 @@ var init_run_command = __esm(() => {
|
|
|
105829
106200
|
GIT_PAGER: "cat",
|
|
105830
106201
|
NO_COLOR: "1"
|
|
105831
106202
|
};
|
|
106203
|
+
gitQueues = new Map;
|
|
105832
106204
|
});
|
|
105833
106205
|
|
|
105834
106206
|
// src/daemon/infrastructure/git/types.ts
|
|
@@ -105838,6 +106210,9 @@ function makeGitStateKey(machineId, workingDir) {
|
|
|
105838
106210
|
var FULL_DIFF_MAX_BYTES = 500000, COMMITS_PER_PAGE = 20;
|
|
105839
106211
|
|
|
105840
106212
|
// src/daemon/infrastructure/git/git-reader.ts
|
|
106213
|
+
function runGit2(args2, cwd, options) {
|
|
106214
|
+
return runGit(cwd ? args2 : args2, cwd, { ...options, readOnly: true });
|
|
106215
|
+
}
|
|
105841
106216
|
function repoArgs(repoSlug) {
|
|
105842
106217
|
return repoSlug ? ["--repo", repoSlug] : [];
|
|
105843
106218
|
}
|
|
@@ -105854,14 +106229,14 @@ function isEmptyRepo(stderr) {
|
|
|
105854
106229
|
return stderr.includes("does not have any commits yet") || stderr.includes("no commits yet") || stderr.includes("ambiguous argument 'HEAD'") || stderr.includes("unknown revision or path");
|
|
105855
106230
|
}
|
|
105856
106231
|
async function listUntrackedFiles(workingDir) {
|
|
105857
|
-
const result = await
|
|
106232
|
+
const result = await runGit2(["ls-files", "--others", "--exclude-standard"], workingDir);
|
|
105858
106233
|
if ("error" in result)
|
|
105859
106234
|
return [];
|
|
105860
106235
|
return result.stdout.split(`
|
|
105861
106236
|
`).map((line) => line.trim()).filter(Boolean);
|
|
105862
106237
|
}
|
|
105863
106238
|
async function getUntrackedFileDiff(workingDir, filePath) {
|
|
105864
|
-
const result = await
|
|
106239
|
+
const result = await runGit2(["diff", "--no-index", "--", NULL_DEVICE, filePath], workingDir, {
|
|
105865
106240
|
successExitCodes: [0, 1]
|
|
105866
106241
|
});
|
|
105867
106242
|
if ("error" in result)
|
|
@@ -105922,7 +106297,7 @@ function truncateDiffContent(raw) {
|
|
|
105922
106297
|
return { status: "available", content: raw, truncated: false };
|
|
105923
106298
|
}
|
|
105924
106299
|
async function runTrackedHeadDiff(workingDir, args2, options) {
|
|
105925
|
-
const result = await
|
|
106300
|
+
const result = await runGit2(args2, workingDir, options);
|
|
105926
106301
|
if ("error" in result) {
|
|
105927
106302
|
const errMsg = result.error.message;
|
|
105928
106303
|
if (isEmptyRepo(errMsg))
|
|
@@ -105951,13 +106326,13 @@ function classifyError(errMessage) {
|
|
|
105951
106326
|
return { status: "error", message: errMessage.trim() };
|
|
105952
106327
|
}
|
|
105953
106328
|
async function isGitRepo(workingDir) {
|
|
105954
|
-
const result = await
|
|
106329
|
+
const result = await runGit2(["rev-parse", "--git-dir"], workingDir);
|
|
105955
106330
|
if ("error" in result)
|
|
105956
106331
|
return false;
|
|
105957
106332
|
return result.stdout.trim().length > 0;
|
|
105958
106333
|
}
|
|
105959
106334
|
async function getBranch(workingDir) {
|
|
105960
|
-
const result = await
|
|
106335
|
+
const result = await runGit2(["rev-parse", "--abbrev-ref", "HEAD"], workingDir);
|
|
105961
106336
|
if ("error" in result) {
|
|
105962
106337
|
const errMsg = result.error.message;
|
|
105963
106338
|
if (errMsg.includes("unknown revision") || errMsg.includes("No such file or directory") || errMsg.includes("does not have any commits")) {
|
|
@@ -105972,7 +106347,7 @@ async function getBranch(workingDir) {
|
|
|
105972
106347
|
return { status: "available", branch };
|
|
105973
106348
|
}
|
|
105974
106349
|
async function isDirty(workingDir) {
|
|
105975
|
-
const result = await
|
|
106350
|
+
const result = await runGit2(["status", "--porcelain"], workingDir);
|
|
105976
106351
|
if ("error" in result)
|
|
105977
106352
|
return false;
|
|
105978
106353
|
return result.stdout.trim().length > 0;
|
|
@@ -106042,7 +106417,7 @@ async function getRecentCommits(workingDir, count3 = 20, skip = 0) {
|
|
|
106042
106417
|
if (skip > 0)
|
|
106043
106418
|
logArgs.push(`--skip=${skip}`);
|
|
106044
106419
|
logArgs.push(`--format=${format4}`);
|
|
106045
|
-
const result = await
|
|
106420
|
+
const result = await runGit2(logArgs, workingDir);
|
|
106046
106421
|
if ("error" in result) {
|
|
106047
106422
|
return [];
|
|
106048
106423
|
}
|
|
@@ -106064,7 +106439,7 @@ async function getRecentCommits(workingDir, count3 = 20, skip = 0) {
|
|
|
106064
106439
|
return commits;
|
|
106065
106440
|
}
|
|
106066
106441
|
async function getCommitDetail(workingDir, sha) {
|
|
106067
|
-
const result = await
|
|
106442
|
+
const result = await runGit2(["show", sha, "--format=", "--stat", "-p"], workingDir);
|
|
106068
106443
|
if ("error" in result) {
|
|
106069
106444
|
const errMsg = result.error.message;
|
|
106070
106445
|
const classified = classifyError(errMsg);
|
|
@@ -106085,7 +106460,7 @@ async function getCommitDetail(workingDir, sha) {
|
|
|
106085
106460
|
}
|
|
106086
106461
|
async function getCommitMetadata(workingDir, sha) {
|
|
106087
106462
|
const format4 = "%s%x1f%b%x1f%an%x1f%aI";
|
|
106088
|
-
const result = await
|
|
106463
|
+
const result = await runGit2(["log", "-1", `--format=${format4}`, sha], workingDir);
|
|
106089
106464
|
if ("error" in result)
|
|
106090
106465
|
return null;
|
|
106091
106466
|
const output = result.stdout.trim();
|
|
@@ -106111,7 +106486,7 @@ function parseRepoSlug(remoteUrl) {
|
|
|
106111
106486
|
return null;
|
|
106112
106487
|
}
|
|
106113
106488
|
async function getOriginRepoSlug(cwd) {
|
|
106114
|
-
const result = await
|
|
106489
|
+
const result = await runGit2(["remote", "get-url", "origin"], cwd);
|
|
106115
106490
|
if ("error" in result)
|
|
106116
106491
|
return null;
|
|
106117
106492
|
const url3 = result.stdout.trim();
|
|
@@ -106248,7 +106623,7 @@ async function getPRCommits(cwd, prNumber) {
|
|
|
106248
106623
|
}
|
|
106249
106624
|
}
|
|
106250
106625
|
async function getRemotes(cwd) {
|
|
106251
|
-
const result = await
|
|
106626
|
+
const result = await runGit2(["remote", "-v"], cwd);
|
|
106252
106627
|
if ("error" in result)
|
|
106253
106628
|
return [];
|
|
106254
106629
|
if (!result.stdout.trim())
|
|
@@ -106272,14 +106647,14 @@ async function getRemotes(cwd) {
|
|
|
106272
106647
|
return remotes;
|
|
106273
106648
|
}
|
|
106274
106649
|
async function getCommitsAhead(workingDir) {
|
|
106275
|
-
const result = await
|
|
106650
|
+
const result = await runGit2(["rev-list", "--count", "@{upstream}..HEAD"], workingDir);
|
|
106276
106651
|
if ("error" in result)
|
|
106277
106652
|
return 0;
|
|
106278
106653
|
const count3 = parseInt(result.stdout.trim(), 10);
|
|
106279
106654
|
return Number.isNaN(count3) ? 0 : count3;
|
|
106280
106655
|
}
|
|
106281
106656
|
async function getCommitsBehind(workingDir) {
|
|
106282
|
-
const result = await
|
|
106657
|
+
const result = await runGit2(["rev-list", "--count", "HEAD..@{upstream}"], workingDir);
|
|
106283
106658
|
if ("error" in result)
|
|
106284
106659
|
return 0;
|
|
106285
106660
|
const count3 = parseInt(result.stdout.trim(), 10);
|
|
@@ -106373,16 +106748,12 @@ class GitStatePipeline {
|
|
|
106373
106748
|
const results = new Map(preCollected);
|
|
106374
106749
|
if (this.fields.length === 0)
|
|
106375
106750
|
return results;
|
|
106376
|
-
const
|
|
106751
|
+
for (const field of this.fields.filter((f) => !results.has(f.key))) {
|
|
106377
106752
|
try {
|
|
106378
|
-
|
|
106379
|
-
return { key: field.key, raw };
|
|
106753
|
+
results.set(field.key, await field.collect(workingDir));
|
|
106380
106754
|
} catch {
|
|
106381
|
-
|
|
106755
|
+
results.set(field.key, field.defaultValue);
|
|
106382
106756
|
}
|
|
106383
|
-
}));
|
|
106384
|
-
for (const { key, raw } of entries2) {
|
|
106385
|
-
results.set(key, raw);
|
|
106386
106757
|
}
|
|
106387
106758
|
return results;
|
|
106388
106759
|
}
|
|
@@ -107547,16 +107918,16 @@ var init_jsonc = __esm(() => {
|
|
|
107547
107918
|
|
|
107548
107919
|
// src/infrastructure/services/workspace/workspace-resolver.ts
|
|
107549
107920
|
import { readFile as readFile7, readdir, stat as stat3 } from "node:fs/promises";
|
|
107550
|
-
import { join as
|
|
107921
|
+
import { join as join21, basename, resolve as resolve4 } from "node:path";
|
|
107551
107922
|
async function resolveGlobPatternStar(rootDir, cleaned) {
|
|
107552
|
-
const parentDir =
|
|
107923
|
+
const parentDir = join21(rootDir, cleaned.slice(0, -2));
|
|
107553
107924
|
try {
|
|
107554
107925
|
const entries2 = await readdir(parentDir, { withFileTypes: true });
|
|
107555
107926
|
const dirs = [];
|
|
107556
107927
|
for (const entry of entries2) {
|
|
107557
107928
|
if (!entry.isDirectory())
|
|
107558
107929
|
continue;
|
|
107559
|
-
const dirPath =
|
|
107930
|
+
const dirPath = join21(parentDir, entry.name);
|
|
107560
107931
|
if (resolve4(dirPath).startsWith(resolve4(rootDir))) {
|
|
107561
107932
|
dirs.push(dirPath);
|
|
107562
107933
|
}
|
|
@@ -107567,7 +107938,7 @@ async function resolveGlobPatternStar(rootDir, cleaned) {
|
|
|
107567
107938
|
}
|
|
107568
107939
|
}
|
|
107569
107940
|
async function resolveLiteralPath(rootDir, cleaned) {
|
|
107570
|
-
const dir =
|
|
107941
|
+
const dir = join21(rootDir, cleaned);
|
|
107571
107942
|
try {
|
|
107572
107943
|
if (!resolve4(dir).startsWith(resolve4(rootDir)))
|
|
107573
107944
|
return [];
|
|
@@ -107587,7 +107958,7 @@ async function resolveGlobPattern(rootDir, pattern) {
|
|
|
107587
107958
|
}
|
|
107588
107959
|
async function readPackageJson(dir) {
|
|
107589
107960
|
try {
|
|
107590
|
-
const content = await readFile7(
|
|
107961
|
+
const content = await readFile7(join21(dir, "package.json"), "utf-8");
|
|
107591
107962
|
const pkg = JSON.parse(content);
|
|
107592
107963
|
return {
|
|
107593
107964
|
name: pkg.name || basename(dir),
|
|
@@ -107599,7 +107970,7 @@ async function readPackageJson(dir) {
|
|
|
107599
107970
|
}
|
|
107600
107971
|
async function readPnpmWorkspacePatterns(rootDir) {
|
|
107601
107972
|
try {
|
|
107602
|
-
const content = await readFile7(
|
|
107973
|
+
const content = await readFile7(join21(rootDir, "pnpm-workspace.yaml"), "utf-8");
|
|
107603
107974
|
const patterns = [];
|
|
107604
107975
|
let inPackages = false;
|
|
107605
107976
|
for (const line of content.split(`
|
|
@@ -107626,7 +107997,7 @@ async function readPnpmWorkspacePatterns(rootDir) {
|
|
|
107626
107997
|
}
|
|
107627
107998
|
async function readPackageJsonWorkspacePatterns(rootDir) {
|
|
107628
107999
|
try {
|
|
107629
|
-
const content = await readFile7(
|
|
108000
|
+
const content = await readFile7(join21(rootDir, "package.json"), "utf-8");
|
|
107630
108001
|
const pkg = JSON.parse(content);
|
|
107631
108002
|
if (!pkg.workspaces)
|
|
107632
108003
|
return [];
|
|
@@ -107707,11 +108078,11 @@ var MAX_NAME_LENGTH = 256;
|
|
|
107707
108078
|
|
|
107708
108079
|
// src/infrastructure/services/workspace/command-discovery.ts
|
|
107709
108080
|
import { access as access2, readFile as readFile8 } from "node:fs/promises";
|
|
107710
|
-
import { join as
|
|
108081
|
+
import { join as join22, relative, basename as basename2 } from "node:path";
|
|
107711
108082
|
async function detectPackageManager(workingDir) {
|
|
107712
108083
|
for (const { file: file2, manager } of LOCKFILE_MAP) {
|
|
107713
108084
|
try {
|
|
107714
|
-
await access2(
|
|
108085
|
+
await access2(join22(workingDir, file2));
|
|
107715
108086
|
return manager;
|
|
107716
108087
|
} catch {}
|
|
107717
108088
|
}
|
|
@@ -107780,7 +108151,7 @@ function collectRootScriptCommands(scripts, pm, scriptPrefix, rootSw) {
|
|
|
107780
108151
|
}
|
|
107781
108152
|
async function readRootPackageJson(workingDir, pm, scriptPrefix) {
|
|
107782
108153
|
let rootPackageName = basename2(workingDir);
|
|
107783
|
-
const pkg = await readJsonFile(
|
|
108154
|
+
const pkg = await readJsonFile(join22(workingDir, "package.json"), "root package.json");
|
|
107784
108155
|
if (!pkg)
|
|
107785
108156
|
return { commands: [], rootPackageName };
|
|
107786
108157
|
if (pkg.name)
|
|
@@ -107796,7 +108167,7 @@ async function readRootPackageJson(workingDir, pm, scriptPrefix) {
|
|
|
107796
108167
|
}
|
|
107797
108168
|
async function readTurboJson(workingDir, _turboPrefix, _rootSubWorkspace) {
|
|
107798
108169
|
const turboTaskNames = [];
|
|
107799
|
-
const turbo = await readJsonFile(
|
|
108170
|
+
const turbo = await readJsonFile(join22(workingDir, "turbo.json"), "turbo.json");
|
|
107800
108171
|
if (!turbo?.tasks || typeof turbo.tasks !== "object")
|
|
107801
108172
|
return turboTaskNames;
|
|
107802
108173
|
for (const taskName of Object.keys(turbo.tasks)) {
|
|
@@ -107809,7 +108180,7 @@ async function readTurboJson(workingDir, _turboPrefix, _rootSubWorkspace) {
|
|
|
107809
108180
|
async function readDenoJson(workingDir) {
|
|
107810
108181
|
const commands = [];
|
|
107811
108182
|
for (const fileName of ["deno.json", "deno.jsonc"]) {
|
|
107812
|
-
const deno = await readJsonFile(
|
|
108183
|
+
const deno = await readJsonFile(join22(workingDir, fileName), fileName);
|
|
107813
108184
|
if (!deno?.tasks || typeof deno.tasks !== "object")
|
|
107814
108185
|
continue;
|
|
107815
108186
|
const pkgName = deno.name ?? basename2(workingDir);
|
|
@@ -107832,7 +108203,7 @@ async function readMakefile(workingDir) {
|
|
|
107832
108203
|
const commands = [];
|
|
107833
108204
|
for (const fileName of ["Makefile", "makefile"]) {
|
|
107834
108205
|
try {
|
|
107835
|
-
const content = await readFile8(
|
|
108206
|
+
const content = await readFile8(join22(workingDir, fileName), "utf-8");
|
|
107836
108207
|
const targets = parseMakefileTargets(content);
|
|
107837
108208
|
if (targets.length === 0)
|
|
107838
108209
|
continue;
|
|
@@ -110038,7 +110409,7 @@ var init_assert_registered_working_dir = __esm(() => {
|
|
|
110038
110409
|
|
|
110039
110410
|
// src/infrastructure/services/workspace/workspace-path-security.ts
|
|
110040
110411
|
import { realpath } from "node:fs/promises";
|
|
110041
|
-
import { dirname as
|
|
110412
|
+
import { dirname as dirname10, isAbsolute, relative as relative2, resolve as resolve5, sep } from "node:path";
|
|
110042
110413
|
import { gunzipSync } from "node:zlib";
|
|
110043
110414
|
function validateRelativePathSegments(filePath) {
|
|
110044
110415
|
if (filePath.includes("\x00"))
|
|
@@ -110066,7 +110437,7 @@ function assertContained(workspaceRoot, targetPath) {
|
|
|
110066
110437
|
return { ok: true };
|
|
110067
110438
|
}
|
|
110068
110439
|
async function resolveNonExistentTarget(workspaceRoot, candidate) {
|
|
110069
|
-
let current =
|
|
110440
|
+
let current = dirname10(candidate);
|
|
110070
110441
|
for (;; ) {
|
|
110071
110442
|
try {
|
|
110072
110443
|
const ancestorReal = await realpath(current);
|
|
@@ -110084,7 +110455,7 @@ async function resolveNonExistentTarget(workspaceRoot, candidate) {
|
|
|
110084
110455
|
if (code2 !== "ENOENT") {
|
|
110085
110456
|
return { ok: false, error: "Invalid file path" };
|
|
110086
110457
|
}
|
|
110087
|
-
const parent =
|
|
110458
|
+
const parent = dirname10(current);
|
|
110088
110459
|
if (parent === current) {
|
|
110089
110460
|
return { ok: false, error: "Path escapes workspace" };
|
|
110090
110461
|
}
|
|
@@ -110895,16 +111266,16 @@ var require_ignore = __commonJS((exports, module) => {
|
|
|
110895
111266
|
// src/infrastructure/services/workspace/workspace-ignore.ts
|
|
110896
111267
|
import { promises as fsPromises } from "node:fs";
|
|
110897
111268
|
import { readFile as readFile10 } from "node:fs/promises";
|
|
110898
|
-
import { homedir as
|
|
111269
|
+
import { homedir as homedir8 } from "node:os";
|
|
110899
111270
|
import path3 from "node:path";
|
|
110900
111271
|
function normalizeRelativePath(relativePath) {
|
|
110901
111272
|
return relativePath.replace(/\\/g, "/").replace(/^\.?\//, "").replace(/\/+$/, "");
|
|
110902
111273
|
}
|
|
110903
111274
|
function expandUserPath(filePath) {
|
|
110904
111275
|
if (filePath === "~")
|
|
110905
|
-
return
|
|
111276
|
+
return homedir8();
|
|
110906
111277
|
if (filePath.startsWith("~/"))
|
|
110907
|
-
return path3.join(
|
|
111278
|
+
return path3.join(homedir8(), filePath.slice(2));
|
|
110908
111279
|
return filePath;
|
|
110909
111280
|
}
|
|
110910
111281
|
function readExcludesFileFromGitconfig(content) {
|
|
@@ -110935,11 +111306,11 @@ async function readGitconfigExcludesFilePath(configPath) {
|
|
|
110935
111306
|
return path3.isAbsolute(raw) ? expandUserPath(raw) : path3.resolve(path3.dirname(configPath), raw);
|
|
110936
111307
|
}
|
|
110937
111308
|
async function resolveGitExtraExcludeFilePaths(rootDir) {
|
|
110938
|
-
const globalConfig2 = process.env.GIT_CONFIG_GLOBAL?.length ? process.env.GIT_CONFIG_GLOBAL : path3.join(
|
|
111309
|
+
const globalConfig2 = process.env.GIT_CONFIG_GLOBAL?.length ? process.env.GIT_CONFIG_GLOBAL : path3.join(homedir8(), ".gitconfig");
|
|
110939
111310
|
const localConfig = path3.join(rootDir, ".git", "config");
|
|
110940
111311
|
let excludesFile = await readGitconfigExcludesFilePath(localConfig) ?? await readGitconfigExcludesFilePath(globalConfig2);
|
|
110941
111312
|
if (!excludesFile) {
|
|
110942
|
-
excludesFile = path3.join(process.env.XDG_CONFIG_HOME?.length ? process.env.XDG_CONFIG_HOME : path3.join(
|
|
111313
|
+
excludesFile = path3.join(process.env.XDG_CONFIG_HOME?.length ? process.env.XDG_CONFIG_HOME : path3.join(homedir8(), ".config"), "git", "ignore");
|
|
110943
111314
|
}
|
|
110944
111315
|
const candidates = [excludesFile, path3.join(rootDir, ".git", "info", "exclude")];
|
|
110945
111316
|
const existing = [];
|
|
@@ -111391,7 +111762,8 @@ function porcelainUntrackedDeletedEvents(args2) {
|
|
|
111391
111762
|
}
|
|
111392
111763
|
async function readGitHead(workTree) {
|
|
111393
111764
|
const result = await runGit(["rev-parse", "HEAD"], workTree, {
|
|
111394
|
-
timeout: GIT_POLL_TIMEOUT_MS
|
|
111765
|
+
timeout: GIT_POLL_TIMEOUT_MS,
|
|
111766
|
+
readOnly: true
|
|
111395
111767
|
});
|
|
111396
111768
|
if ("error" in result) {
|
|
111397
111769
|
if (isEmptyRepoHeadError(result.error))
|
|
@@ -111415,7 +111787,10 @@ async function readGitPorcelainStatus(node) {
|
|
|
111415
111787
|
const args2 = ["status", "--porcelain=v1", "-z", "-uall", "--"];
|
|
111416
111788
|
if (node.pathspec.length > 0)
|
|
111417
111789
|
args2.push(...node.pathspec);
|
|
111418
|
-
const result = await runGit(args2, node.workTree, {
|
|
111790
|
+
const result = await runGit(args2, node.workTree, {
|
|
111791
|
+
timeout: GIT_POLL_TIMEOUT_MS,
|
|
111792
|
+
readOnly: true
|
|
111793
|
+
});
|
|
111419
111794
|
if ("error" in result) {
|
|
111420
111795
|
throw new GitWorkspaceCommandError({
|
|
111421
111796
|
operation: "readGitPorcelainStatus",
|
|
@@ -111553,35 +111928,31 @@ function createGitWorkspaceChangeSource(options) {
|
|
|
111553
111928
|
let needsReconcile = false;
|
|
111554
111929
|
let tickHadFailure = false;
|
|
111555
111930
|
let maxNodeFailures = 0;
|
|
111556
|
-
const
|
|
111557
|
-
|
|
111558
|
-
|
|
111559
|
-
|
|
111560
|
-
|
|
111561
|
-
|
|
111562
|
-
|
|
111563
|
-
|
|
111564
|
-
|
|
111565
|
-
|
|
111566
|
-
|
|
111567
|
-
|
|
111568
|
-
|
|
111569
|
-
needsReconcile
|
|
111570
|
-
|
|
111571
|
-
|
|
111572
|
-
|
|
111573
|
-
|
|
111574
|
-
|
|
111575
|
-
|
|
111576
|
-
|
|
111577
|
-
|
|
111578
|
-
|
|
111579
|
-
|
|
111580
|
-
|
|
111581
|
-
const prevFailures = nodeFailureCounts.get(node.workTree) ?? 0;
|
|
111582
|
-
const nextFailures = prevFailures + 1;
|
|
111583
|
-
nodeFailureCounts.set(node.workTree, nextFailures);
|
|
111584
|
-
maxNodeFailures = Math.max(maxNodeFailures, nextFailures);
|
|
111931
|
+
for (const node of nodes) {
|
|
111932
|
+
try {
|
|
111933
|
+
const prev = state.get(node.workTree) ?? {
|
|
111934
|
+
prevEntries: [],
|
|
111935
|
+
prevHead: { head: null },
|
|
111936
|
+
baselineEstablished: false
|
|
111937
|
+
};
|
|
111938
|
+
const result = await pollGitWorkspaceNode({
|
|
111939
|
+
options,
|
|
111940
|
+
node,
|
|
111941
|
+
prev
|
|
111942
|
+
});
|
|
111943
|
+
allEvents.push(...result.events);
|
|
111944
|
+
if (result.needsReconcile)
|
|
111945
|
+
needsReconcile = true;
|
|
111946
|
+
state.set(node.workTree, result.nextState);
|
|
111947
|
+
nodeFailureCounts.set(node.workTree, 0);
|
|
111948
|
+
} catch (reason) {
|
|
111949
|
+
tickHadFailure = true;
|
|
111950
|
+
options.onError?.(reason);
|
|
111951
|
+
const prevFailures = nodeFailureCounts.get(node.workTree) ?? 0;
|
|
111952
|
+
const nextFailures = prevFailures + 1;
|
|
111953
|
+
nodeFailureCounts.set(node.workTree, nextFailures);
|
|
111954
|
+
maxNodeFailures = Math.max(maxNodeFailures, nextFailures);
|
|
111955
|
+
}
|
|
111585
111956
|
}
|
|
111586
111957
|
if (tickHadFailure) {
|
|
111587
111958
|
consecutiveFailureTicks += 1;
|
|
@@ -111639,7 +112010,7 @@ function createGitWorkspaceChangeSource(options) {
|
|
|
111639
112010
|
}
|
|
111640
112011
|
};
|
|
111641
112012
|
}
|
|
111642
|
-
var DEFAULT_POLL_INTERVAL_MS =
|
|
112013
|
+
var DEFAULT_POLL_INTERVAL_MS = 3000, MAX_BACKOFF_MS = 30000, PERSISTENT_FAILURE_THRESHOLD = 3;
|
|
111643
112014
|
var init_git_workspace_change_source = __esm(() => {
|
|
111644
112015
|
init_git_workspace_porcelain();
|
|
111645
112016
|
});
|
|
@@ -112068,9 +112439,9 @@ class NodeFsHandler {
|
|
|
112068
112439
|
if (this.fsw.closed) {
|
|
112069
112440
|
return;
|
|
112070
112441
|
}
|
|
112071
|
-
const
|
|
112442
|
+
const dirname12 = sp.dirname(file2);
|
|
112072
112443
|
const basename4 = sp.basename(file2);
|
|
112073
|
-
const parent = this.fsw._getWatchedDir(
|
|
112444
|
+
const parent = this.fsw._getWatchedDir(dirname12);
|
|
112074
112445
|
let prevStats = stats;
|
|
112075
112446
|
if (parent.has(basename4))
|
|
112076
112447
|
return;
|
|
@@ -112097,7 +112468,7 @@ class NodeFsHandler {
|
|
|
112097
112468
|
prevStats = newStats2;
|
|
112098
112469
|
}
|
|
112099
112470
|
} catch (error51) {
|
|
112100
|
-
this.fsw._remove(
|
|
112471
|
+
this.fsw._remove(dirname12, basename4);
|
|
112101
112472
|
}
|
|
112102
112473
|
} else if (parent.has(basename4)) {
|
|
112103
112474
|
const at = newStats.atimeMs;
|
|
@@ -113486,8 +113857,8 @@ function diffPathIndexes(previous, next4) {
|
|
|
113486
113857
|
// src/infrastructure/services/workspace/workspace-sync-state.ts
|
|
113487
113858
|
import { createHash as createHash7, randomUUID as randomUUID9 } from "node:crypto";
|
|
113488
113859
|
import * as fs11 from "node:fs/promises";
|
|
113489
|
-
import { homedir as
|
|
113490
|
-
import { join as
|
|
113860
|
+
import { homedir as homedir9 } from "node:os";
|
|
113861
|
+
import { join as join25 } from "node:path";
|
|
113491
113862
|
function workspaceKeyFor(workingDir) {
|
|
113492
113863
|
const normalized = normalizeWorkingDirForLookup(workingDir);
|
|
113493
113864
|
return createHash7("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
@@ -113501,10 +113872,10 @@ function buildPathIndex(entries2) {
|
|
|
113501
113872
|
}
|
|
113502
113873
|
function manifestPath(machineId, workingDir) {
|
|
113503
113874
|
const key = workspaceKeyFor(workingDir);
|
|
113504
|
-
return
|
|
113875
|
+
return join25(SYNC_STATE_DIR, machineId, key, "manifest.json");
|
|
113505
113876
|
}
|
|
113506
113877
|
async function ensureDir(filePath) {
|
|
113507
|
-
await fs11.mkdir(
|
|
113878
|
+
await fs11.mkdir(join25(filePath, ".."), { recursive: true, mode: 448 });
|
|
113508
113879
|
}
|
|
113509
113880
|
async function loadWorkspaceSyncManifest(machineId, workingDir) {
|
|
113510
113881
|
try {
|
|
@@ -113564,7 +113935,7 @@ function entriesFromPathIndex(paths) {
|
|
|
113564
113935
|
}
|
|
113565
113936
|
var SYNC_STATE_VERSION = "2", SYNC_STATE_DIR;
|
|
113566
113937
|
var init_workspace_sync_state = __esm(() => {
|
|
113567
|
-
SYNC_STATE_DIR =
|
|
113938
|
+
SYNC_STATE_DIR = join25(homedir9(), ".chatroom", "sync-state");
|
|
113568
113939
|
});
|
|
113569
113940
|
|
|
113570
113941
|
// src/infrastructure/services/workspace/workspace-file-tree-coordinator.ts
|
|
@@ -113941,12 +114312,12 @@ var init_durable_coalescing_state_schema = __esm(() => {
|
|
|
113941
114312
|
});
|
|
113942
114313
|
|
|
113943
114314
|
// src/daemon/infrastructure/outbox/lib/durable-coalescing-state-store.ts
|
|
113944
|
-
import { mkdirSync as
|
|
113945
|
-
import { dirname as
|
|
113946
|
-
import { DatabaseSync } from "node:sqlite";
|
|
114315
|
+
import { mkdirSync as mkdirSync7 } from "node:fs";
|
|
114316
|
+
import { dirname as dirname13 } from "node:path";
|
|
114317
|
+
import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
|
|
113947
114318
|
function openDurableCoalescingStateStore(path8) {
|
|
113948
|
-
|
|
113949
|
-
const db = new
|
|
114319
|
+
mkdirSync7(dirname13(path8), { recursive: true });
|
|
114320
|
+
const db = new DatabaseSync2(path8);
|
|
113950
114321
|
for (const sql of DURABLE_COALESCING_STATE_MIGRATIONS)
|
|
113951
114322
|
db.exec(sql);
|
|
113952
114323
|
db.prepare("UPDATE coalescing_outbox_entries SET status='pending' WHERE status='in_flight'").run();
|
|
@@ -113963,13 +114334,6 @@ var init_durable_coalescing_state_store = __esm(() => {
|
|
|
113963
114334
|
init_durable_coalescing_state_schema();
|
|
113964
114335
|
});
|
|
113965
114336
|
|
|
113966
|
-
// src/daemon/infrastructure/outbox/lib/outbox-retry-backoff.ts
|
|
113967
|
-
function computeExponentialRetryDelayMs(attempt, retryDelayMs, maxRetryDelayMs) {
|
|
113968
|
-
const exponent = Math.min(Math.max(0, attempt), MAX_RETRY_EXPONENT);
|
|
113969
|
-
return Math.min(retryDelayMs * 2 ** exponent, maxRetryDelayMs);
|
|
113970
|
-
}
|
|
113971
|
-
var MAX_RETRY_EXPONENT = 20;
|
|
113972
|
-
|
|
113973
114337
|
// src/daemon/infrastructure/outbox/lib/coalescing-state-outbox.ts
|
|
113974
114338
|
function createCoalescingStateOutbox(options) {
|
|
113975
114339
|
const durable = [options.store, options.deliveryKey, options.serialize, options.deserialize];
|
|
@@ -114146,14 +114510,6 @@ var init_keyed_coalescing_state_outbox_registry = __esm(() => {
|
|
|
114146
114510
|
init_coalescing_state_outbox();
|
|
114147
114511
|
});
|
|
114148
114512
|
|
|
114149
|
-
// src/daemon/infrastructure/outbox/outbox-db-path.ts
|
|
114150
|
-
import { homedir as homedir9 } from "node:os";
|
|
114151
|
-
import { join as join25 } from "node:path";
|
|
114152
|
-
function resolveOutboxDbPath(machineId, kind) {
|
|
114153
|
-
return join25(homedir9(), ".chatroom", "daemon", machineId, `outbox-${kind}.sqlite`);
|
|
114154
|
-
}
|
|
114155
|
-
var init_outbox_db_path = () => {};
|
|
114156
|
-
|
|
114157
114513
|
// src/daemon/infrastructure/outbox/workspace-file-tree-checkpoint-outbox.ts
|
|
114158
114514
|
function createWorkspaceFileTreeCheckpointOutboxRegistry(machineId, createSend, options) {
|
|
114159
114515
|
return createKeyedCoalescingStateOutboxRegistry({
|
|
@@ -114175,193 +114531,6 @@ var init_workspace_file_tree_checkpoint_outbox = __esm(() => {
|
|
|
114175
114531
|
WORKSPACE_FILE_TREE_CHECKPOINT_OUTBOX_MAX_RETRY_DELAY_MS = 5 * 60000;
|
|
114176
114532
|
});
|
|
114177
114533
|
|
|
114178
|
-
// src/daemon/infrastructure/outbox/lib/durable-fifo-queue-schema.ts
|
|
114179
|
-
var DURABLE_FIFO_QUEUE_MIGRATIONS;
|
|
114180
|
-
var init_durable_fifo_queue_schema = __esm(() => {
|
|
114181
|
-
DURABLE_FIFO_QUEUE_MIGRATIONS = [
|
|
114182
|
-
`CREATE TABLE IF NOT EXISTS schema_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)`,
|
|
114183
|
-
`CREATE TABLE IF NOT EXISTS fifo_outbox_entries (id INTEGER PRIMARY KEY AUTOINCREMENT, delivery_key TEXT NOT NULL, payload_json TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'pending', attempts INTEGER NOT NULL DEFAULT 0, last_error TEXT, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL)`,
|
|
114184
|
-
`CREATE INDEX IF NOT EXISTS idx_fifo_outbox_pending ON fifo_outbox_entries(delivery_key, status, id)`
|
|
114185
|
-
];
|
|
114186
|
-
});
|
|
114187
|
-
|
|
114188
|
-
// src/daemon/infrastructure/outbox/lib/durable-fifo-queue-store.ts
|
|
114189
|
-
import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
|
|
114190
|
-
import { mkdirSync as mkdirSync7 } from "node:fs";
|
|
114191
|
-
import { dirname as dirname13 } from "node:path";
|
|
114192
|
-
function openDurableFifoQueueStore(dbPath) {
|
|
114193
|
-
mkdirSync7(dirname13(dbPath), { recursive: true });
|
|
114194
|
-
const db = new DatabaseSync2(dbPath);
|
|
114195
|
-
for (const sql of DURABLE_FIFO_QUEUE_MIGRATIONS)
|
|
114196
|
-
db.exec(sql);
|
|
114197
|
-
db.prepare("UPDATE fifo_outbox_entries SET status='pending', updated_at=? WHERE status='in_flight'").run(Date.now());
|
|
114198
|
-
return {
|
|
114199
|
-
enqueue: (key, payloadJson) => {
|
|
114200
|
-
const now = Date.now();
|
|
114201
|
-
return Number(db.prepare("INSERT INTO fifo_outbox_entries(delivery_key,payload_json,created_at,updated_at) VALUES(?,?,?,?) RETURNING id").get(key, payloadJson, now, now).id);
|
|
114202
|
-
},
|
|
114203
|
-
claimNextBatch: (key, limit) => db.prepare("UPDATE fifo_outbox_entries SET status='in_flight', attempts=attempts+1, updated_at=? WHERE id IN (SELECT id FROM fifo_outbox_entries WHERE delivery_key=? AND status='pending' ORDER BY id LIMIT ?) RETURNING id, delivery_key as deliveryKey, payload_json as payloadJson, attempts").all(Date.now(), key, limit),
|
|
114204
|
-
markDone: (id3) => {
|
|
114205
|
-
db.prepare("DELETE FROM fifo_outbox_entries WHERE id=?").run(id3);
|
|
114206
|
-
},
|
|
114207
|
-
markPending: (id3) => {
|
|
114208
|
-
db.prepare("UPDATE fifo_outbox_entries SET status='pending', last_error=NULL, updated_at=? WHERE id=?").run(Date.now(), id3);
|
|
114209
|
-
},
|
|
114210
|
-
updatePayload: (id3, payloadJson) => {
|
|
114211
|
-
db.prepare("UPDATE fifo_outbox_entries SET payload_json=?, updated_at=? WHERE id=?").run(payloadJson, Date.now(), id3);
|
|
114212
|
-
},
|
|
114213
|
-
markPendingRetry: (id3, error51) => {
|
|
114214
|
-
db.prepare("UPDATE fifo_outbox_entries SET status='pending', last_error=?, updated_at=? WHERE id=?").run(String(error51), Date.now(), id3);
|
|
114215
|
-
},
|
|
114216
|
-
listPendingForRecovery: (key) => db.prepare("SELECT id, delivery_key as deliveryKey, payload_json as payloadJson, attempts FROM fifo_outbox_entries WHERE delivery_key=? AND status IN ('pending','in_flight') ORDER BY id").all(key),
|
|
114217
|
-
close: () => db.close()
|
|
114218
|
-
};
|
|
114219
|
-
}
|
|
114220
|
-
var init_durable_fifo_queue_store = __esm(() => {
|
|
114221
|
-
init_durable_fifo_queue_schema();
|
|
114222
|
-
});
|
|
114223
|
-
|
|
114224
|
-
// src/daemon/infrastructure/outbox/lib/fifo-batched-outbox.ts
|
|
114225
|
-
function createFifoBatchedOutbox(o) {
|
|
114226
|
-
const waiters = new Map;
|
|
114227
|
-
let running3;
|
|
114228
|
-
let stopped = false;
|
|
114229
|
-
let retryTimer;
|
|
114230
|
-
let retryAttempt = 0;
|
|
114231
|
-
const retryDelay = () => computeExponentialRetryDelayMs(retryAttempt++, o.retryDelayMs ?? 500, o.maxRetryDelayMs ?? 5000);
|
|
114232
|
-
const scheduleRetry = () => {
|
|
114233
|
-
if (!stopped && !retryTimer) {
|
|
114234
|
-
retryTimer = setTimeout(() => {
|
|
114235
|
-
retryTimer = undefined;
|
|
114236
|
-
drain2().catch(() => {
|
|
114237
|
-
return;
|
|
114238
|
-
});
|
|
114239
|
-
}, retryDelay());
|
|
114240
|
-
retryTimer.unref?.();
|
|
114241
|
-
}
|
|
114242
|
-
};
|
|
114243
|
-
const drain2 = async () => {
|
|
114244
|
-
if (running3)
|
|
114245
|
-
return running3;
|
|
114246
|
-
running3 = (async () => {
|
|
114247
|
-
while (true) {
|
|
114248
|
-
const rows = o.store.claimNextBatch(o.deliveryKey, o.batchSize);
|
|
114249
|
-
if (!rows.length)
|
|
114250
|
-
break;
|
|
114251
|
-
try {
|
|
114252
|
-
const results = await o.send(rows.map((r) => o.deserialize(r.payloadJson)));
|
|
114253
|
-
let hasRetry = false;
|
|
114254
|
-
for (let i2 = 0;i2 < results.length; i2++) {
|
|
114255
|
-
const item = o.deserialize(rows[i2].payloadJson);
|
|
114256
|
-
const outcome = o.classifyOutcome?.(results[i2], item) ?? { kind: "success" };
|
|
114257
|
-
if (outcome.kind === "retry") {
|
|
114258
|
-
o.store.updatePayload(rows[i2].id, o.serialize(outcome.item));
|
|
114259
|
-
o.store.markPending(rows[i2].id);
|
|
114260
|
-
hasRetry = true;
|
|
114261
|
-
continue;
|
|
114262
|
-
}
|
|
114263
|
-
o.store.markDone(rows[i2].id);
|
|
114264
|
-
waiters.get(rows[i2].id)?.resolve(results[i2]);
|
|
114265
|
-
waiters.delete(rows[i2].id);
|
|
114266
|
-
}
|
|
114267
|
-
for (let i2 = results.length;i2 < rows.length; i2++)
|
|
114268
|
-
o.store.markPending(rows[i2].id);
|
|
114269
|
-
if (hasRetry) {
|
|
114270
|
-
scheduleRetry();
|
|
114271
|
-
break;
|
|
114272
|
-
}
|
|
114273
|
-
retryAttempt = 0;
|
|
114274
|
-
} catch (e) {
|
|
114275
|
-
o.onError?.(e);
|
|
114276
|
-
for (const r of rows)
|
|
114277
|
-
o.store.markPendingRetry(r.id, e);
|
|
114278
|
-
scheduleRetry();
|
|
114279
|
-
break;
|
|
114280
|
-
}
|
|
114281
|
-
}
|
|
114282
|
-
})().finally(() => {
|
|
114283
|
-
running3 = undefined;
|
|
114284
|
-
});
|
|
114285
|
-
return running3;
|
|
114286
|
-
};
|
|
114287
|
-
const enqueue = (item) => {
|
|
114288
|
-
if (stopped)
|
|
114289
|
-
return Promise.reject(new Error("Outbox is stopped"));
|
|
114290
|
-
const id3 = o.store.enqueue(o.deliveryKey, o.serialize(item));
|
|
114291
|
-
const p = new Promise((resolve8, reject) => waiters.set(id3, { resolve: resolve8, reject }));
|
|
114292
|
-
drain2().catch(() => {
|
|
114293
|
-
return;
|
|
114294
|
-
});
|
|
114295
|
-
return p;
|
|
114296
|
-
};
|
|
114297
|
-
const flushNow = async () => {
|
|
114298
|
-
while (o.store.listPendingForRecovery(o.deliveryKey).length) {
|
|
114299
|
-
await drain2();
|
|
114300
|
-
}
|
|
114301
|
-
};
|
|
114302
|
-
const stop4 = async () => {
|
|
114303
|
-
if (stopped)
|
|
114304
|
-
return;
|
|
114305
|
-
if (retryTimer)
|
|
114306
|
-
clearTimeout(retryTimer);
|
|
114307
|
-
retryTimer = undefined;
|
|
114308
|
-
await flushNow();
|
|
114309
|
-
stopped = true;
|
|
114310
|
-
};
|
|
114311
|
-
return { enqueue, flushNow, stop: stop4 };
|
|
114312
|
-
}
|
|
114313
|
-
var init_fifo_batched_outbox = () => {};
|
|
114314
|
-
|
|
114315
|
-
// src/daemon/infrastructure/outbox/lib/keyed-fifo-batched-outbox-registry.ts
|
|
114316
|
-
function createKeyedFifoBatchedOutboxRegistry(o) {
|
|
114317
|
-
const boxes = new Map;
|
|
114318
|
-
const get13 = (key) => {
|
|
114319
|
-
let b = boxes.get(key);
|
|
114320
|
-
if (!b) {
|
|
114321
|
-
b = createFifoBatchedOutbox({
|
|
114322
|
-
batchSize: o.batchSize,
|
|
114323
|
-
send: o.createSend(key),
|
|
114324
|
-
store: o.store,
|
|
114325
|
-
deliveryKey: key,
|
|
114326
|
-
serialize: o.serialize,
|
|
114327
|
-
deserialize: o.deserialize,
|
|
114328
|
-
retryDelayMs: o.retryDelayMs,
|
|
114329
|
-
maxRetryDelayMs: o.maxRetryDelayMs,
|
|
114330
|
-
onError: (e) => o.onError?.(key, e),
|
|
114331
|
-
classifyOutcome: o.classifyOutcome
|
|
114332
|
-
});
|
|
114333
|
-
boxes.set(key, b);
|
|
114334
|
-
}
|
|
114335
|
-
return b;
|
|
114336
|
-
};
|
|
114337
|
-
const stop4 = async (k) => {
|
|
114338
|
-
const b = boxes.get(k);
|
|
114339
|
-
if (b) {
|
|
114340
|
-
await b.stop();
|
|
114341
|
-
boxes.delete(k);
|
|
114342
|
-
}
|
|
114343
|
-
};
|
|
114344
|
-
return {
|
|
114345
|
-
enqueue: (k, i2) => get13(k).enqueue(i2),
|
|
114346
|
-
flushNow: async (k) => {
|
|
114347
|
-
if (k)
|
|
114348
|
-
await get13(k).flushNow();
|
|
114349
|
-
else
|
|
114350
|
-
for (const b of boxes.values())
|
|
114351
|
-
await b.flushNow();
|
|
114352
|
-
},
|
|
114353
|
-
stop: stop4,
|
|
114354
|
-
stopAll: async () => {
|
|
114355
|
-
for (const k of [...boxes.keys()])
|
|
114356
|
-
await stop4(k);
|
|
114357
|
-
o.store.close();
|
|
114358
|
-
}
|
|
114359
|
-
};
|
|
114360
|
-
}
|
|
114361
|
-
var init_keyed_fifo_batched_outbox_registry = __esm(() => {
|
|
114362
|
-
init_fifo_batched_outbox();
|
|
114363
|
-
});
|
|
114364
|
-
|
|
114365
114534
|
// src/daemon/infrastructure/outbox/workspace-file-tree-delta-outbox.ts
|
|
114366
114535
|
function createWorkspaceFileTreeDeltaOutboxRegistry(machineId, createSend, options) {
|
|
114367
114536
|
const store = openDurableFifoQueueStore(resolveOutboxDbPath(machineId, "file-tree-delta"));
|
|
@@ -114396,6 +114565,8 @@ var init_workspace_file_tree_delta_outbox = __esm(() => {
|
|
|
114396
114565
|
var init_outbox = __esm(() => {
|
|
114397
114566
|
init_workspace_file_tree_checkpoint_outbox();
|
|
114398
114567
|
init_workspace_file_tree_delta_outbox();
|
|
114568
|
+
init_agent_lifecycle_outbox();
|
|
114569
|
+
init_agent_lifecycle_send();
|
|
114399
114570
|
});
|
|
114400
114571
|
|
|
114401
114572
|
// ../../services/backend/src/domain/workspace-file-tree/types.ts
|
|
@@ -115804,7 +115975,8 @@ var init_command_run_subscription = __esm(() => {
|
|
|
115804
115975
|
// src/daemon/entry/task-delivery/task-delivery-logic.ts
|
|
115805
115976
|
function isPendingAliveRunningTask(task) {
|
|
115806
115977
|
const { agentConfig, status: status3 } = task;
|
|
115807
|
-
|
|
115978
|
+
const op = getNativeDeliverySession()?.agentOperationalReadModel?.get(task.chatroomId, agentConfig.role);
|
|
115979
|
+
return status3 === "pending" && (agentConfig.spawnedAgentPid != null || op?.isAlive === true) && isOperationalDesiredRunning(op);
|
|
115808
115980
|
}
|
|
115809
115981
|
function isSlotUnavailableForPid(slot, pid, isPidAlive, now = Date.now()) {
|
|
115810
115982
|
if (!slot) {
|
|
@@ -115847,7 +116019,8 @@ function isNativeAgentSlotDown(task, health, now = Date.now()) {
|
|
|
115847
116019
|
function isNativeActiveTaskAgentDown(task, health, now) {
|
|
115848
116020
|
if (!isNativeHarness(task.agentConfig.agentHarness))
|
|
115849
116021
|
return false;
|
|
115850
|
-
|
|
116022
|
+
const op = getNativeDeliverySession()?.agentOperationalReadModel?.get(task.chatroomId, task.agentConfig.role);
|
|
116023
|
+
if (!isOperationalDesiredRunning(op))
|
|
115851
116024
|
return false;
|
|
115852
116025
|
if (!isNativeRevivableTaskStatus(task))
|
|
115853
116026
|
return false;
|
|
@@ -115871,7 +116044,8 @@ function isNativePendingTaskNeedingWake(task) {
|
|
|
115871
116044
|
return false;
|
|
115872
116045
|
if (task.status !== "pending")
|
|
115873
116046
|
return false;
|
|
115874
|
-
|
|
116047
|
+
const op = getNativeDeliverySession()?.agentOperationalReadModel?.get(task.chatroomId, task.agentConfig.role);
|
|
116048
|
+
if (isOperationalDesiredRunning(op))
|
|
115875
116049
|
return false;
|
|
115876
116050
|
return Boolean(task.agentConfig.workingDir);
|
|
115877
116051
|
}
|
|
@@ -115947,10 +116121,10 @@ function listTasksReadyForNudge(tasks, now, cooldown, getSlot) {
|
|
|
115947
116121
|
}
|
|
115948
116122
|
var PENDING_IDLE_NUDGE_MS = 15000, NUDGE_COOLDOWN_MS = 60000;
|
|
115949
116123
|
var init_task_delivery_logic = __esm(() => {
|
|
115950
|
-
init_assigned_task();
|
|
115951
116124
|
init_check_agent_slot();
|
|
115952
116125
|
init_predicates();
|
|
115953
116126
|
init_agent_process_manager();
|
|
116127
|
+
init_native_delivery_session_registry();
|
|
115954
116128
|
init_native_ready_invariant();
|
|
115955
116129
|
init_native_task_injector_logic();
|
|
115956
116130
|
});
|
|
@@ -116050,7 +116224,7 @@ function runNativeWakeEffect(task, runtime4, effectContext2, agentMgr) {
|
|
|
116050
116224
|
if (!ctx)
|
|
116051
116225
|
return;
|
|
116052
116226
|
const { chatroomId, agentConfig, role, workingDir, wantResume } = ctx;
|
|
116053
|
-
console.log(`[TaskMonitor] native wake ${role}@${chatroomId} —
|
|
116227
|
+
console.log(`[TaskMonitor] native wake ${role}@${chatroomId} — operational_state=stopped with pending task ${task.taskId}`);
|
|
116054
116228
|
exports_Runtime.runFork(runtime4)(exports_Effect.gen(function* () {
|
|
116055
116229
|
yield* agentMgr.ensureRunning({
|
|
116056
116230
|
chatroomId,
|
|
@@ -116152,6 +116326,31 @@ var init_task_delivery_processor = __esm(() => {
|
|
|
116152
116326
|
init_task_delivery_logic();
|
|
116153
116327
|
});
|
|
116154
116328
|
|
|
116329
|
+
// src/daemon/infrastructure/agent-operational/enrich-snapshot-with-operational.ts
|
|
116330
|
+
function enrichSnapshotWithOperational(snapshot) {
|
|
116331
|
+
const op = getNativeDeliverySession()?.agentOperationalReadModel?.get(snapshot.chatroomId, snapshot.agentConfig.role);
|
|
116332
|
+
if (!op)
|
|
116333
|
+
return snapshot;
|
|
116334
|
+
return { ...snapshot, agentConfig: { ...snapshot.agentConfig, desiredState: isOperationalDesiredRunning(op) ? "running" : "stopped" } };
|
|
116335
|
+
}
|
|
116336
|
+
function enrichSnapshotsWithOperational(snapshots) {
|
|
116337
|
+
return snapshots.map(enrichSnapshotWithOperational);
|
|
116338
|
+
}
|
|
116339
|
+
var init_enrich_snapshot_with_operational = __esm(() => {
|
|
116340
|
+
init_native_delivery_session_registry();
|
|
116341
|
+
});
|
|
116342
|
+
|
|
116343
|
+
// src/daemon/infrastructure/agent-operational/subscribe-machine-agent-operational-status.ts
|
|
116344
|
+
function subscribeMachineAgentOperationalStatus(client4, options, onRows) {
|
|
116345
|
+
return client4.onUpdate(api.machines.subscribeMachineAgentOperationalStatus, { sessionId: options.sessionId, machineId: options.machineId }, (result) => {
|
|
116346
|
+
if (Array.isArray(result))
|
|
116347
|
+
onRows(result);
|
|
116348
|
+
});
|
|
116349
|
+
}
|
|
116350
|
+
var init_subscribe_machine_agent_operational_status = __esm(() => {
|
|
116351
|
+
init_api3();
|
|
116352
|
+
});
|
|
116353
|
+
|
|
116155
116354
|
// src/daemon/infrastructure/inbox/fetch-machine-assigned-task-snapshots.ts
|
|
116156
116355
|
async function fetchMachineAssignedTaskSnapshots(sessionDeps, machineId) {
|
|
116157
116356
|
const result = await sessionDeps.backend.query(api.machines.listMachineAssignedTaskSnapshots, {
|
|
@@ -116321,11 +116520,12 @@ async function handleTaskInboxUpdate(update6, deps) {
|
|
|
116321
116520
|
taskSnapshotState?.applySignalPage(update6.signals, update6.snapshots);
|
|
116322
116521
|
if (update6.snapshots.length === 0)
|
|
116323
116522
|
return;
|
|
116324
|
-
await processTasksUpdate(deps.runtime, deps.effectContext, deps.cooldown, deps.agentMgr, deps.sessionDeps, deps.machineId, "inbox-signal", { snapshots: update6.snapshots });
|
|
116523
|
+
await processTasksUpdate(deps.runtime, deps.effectContext, deps.cooldown, deps.agentMgr, deps.sessionDeps, deps.machineId, "inbox-signal", { snapshots: enrichSnapshotsWithOperational(update6.snapshots) });
|
|
116325
116524
|
}
|
|
116326
116525
|
var init_task_inbox_delivery = __esm(() => {
|
|
116327
116526
|
init_native_delivery_session_registry();
|
|
116328
116527
|
init_task_delivery_processor();
|
|
116528
|
+
init_enrich_snapshot_with_operational();
|
|
116329
116529
|
});
|
|
116330
116530
|
|
|
116331
116531
|
// src/daemon/infrastructure/inbox/task.ts
|
|
@@ -116435,6 +116635,10 @@ var init_task = __esm(() => {
|
|
|
116435
116635
|
|
|
116436
116636
|
// src/daemon/entry/task-inbox-runtime.ts
|
|
116437
116637
|
async function bootstrapMachineAssignedTaskSnapshots(deps) {
|
|
116638
|
+
await deps.sessionDeps.backend.mutation(api.machines.backfillAgentOperationalStatusForMachine, {
|
|
116639
|
+
sessionId: deps.sessionDeps.sessionId,
|
|
116640
|
+
machineId: deps.machineId
|
|
116641
|
+
});
|
|
116438
116642
|
await deps.sessionDeps.backend.mutation(api.machines.syncMachineAssignedTaskSnapshotsMutation, {
|
|
116439
116643
|
sessionId: deps.sessionDeps.sessionId,
|
|
116440
116644
|
machineId: deps.machineId
|
|
@@ -116443,7 +116647,7 @@ async function bootstrapMachineAssignedTaskSnapshots(deps) {
|
|
|
116443
116647
|
deps.taskSnapshotState?.replace(tasks);
|
|
116444
116648
|
if (!tasks.length)
|
|
116445
116649
|
return;
|
|
116446
|
-
await processTasksUpdate(deps.runtime, deps.effectContext, deps.cooldown, deps.agentMgr, deps.sessionDeps, deps.machineId, "bootstrap", { snapshots: tasks });
|
|
116650
|
+
await processTasksUpdate(deps.runtime, deps.effectContext, deps.cooldown, deps.agentMgr, deps.sessionDeps, deps.machineId, "bootstrap", { snapshots: enrichSnapshotsWithOperational(tasks) });
|
|
116447
116651
|
}
|
|
116448
116652
|
function isAbortError(error51) {
|
|
116449
116653
|
return error51 instanceof Error && error51.name === "AbortError";
|
|
@@ -116487,13 +116691,15 @@ var NATIVE_DELIVERY_RECONCILE_MS = 1e4, INBOX_RESTART_INITIAL_MS = 1000, INBOX_R
|
|
|
116487
116691
|
const abort = new AbortController;
|
|
116488
116692
|
let stopped = false;
|
|
116489
116693
|
const taskSnapshotState = new MachineTaskSnapshotState;
|
|
116694
|
+
const agentOperationalReadModel = new AgentOperationalReadModel;
|
|
116490
116695
|
registerNativeDeliverySession({
|
|
116491
116696
|
runtime: runtime4,
|
|
116492
116697
|
effectContext: effectContext2,
|
|
116493
116698
|
agentMgr,
|
|
116494
116699
|
sessionDeps,
|
|
116495
116700
|
machineId: session2.machineId,
|
|
116496
|
-
taskSnapshotState
|
|
116701
|
+
taskSnapshotState,
|
|
116702
|
+
agentOperationalReadModel
|
|
116497
116703
|
});
|
|
116498
116704
|
const cooldown = new RecoveryCooldown;
|
|
116499
116705
|
let inboxUpdateInFlight = false;
|
|
@@ -116535,11 +116741,24 @@ var NATIVE_DELIVERY_RECONCILE_MS = 1e4, INBOX_RESTART_INITIAL_MS = 1000, INBOX_R
|
|
|
116535
116741
|
console.warn("[TaskInbox] bootstrap failed:", error51);
|
|
116536
116742
|
return exports_Effect.void;
|
|
116537
116743
|
}));
|
|
116744
|
+
const unsubscribeOperational = subscribeMachineAgentOperationalStatus(wsClient2, {
|
|
116745
|
+
sessionId: session2.sessionId,
|
|
116746
|
+
machineId: session2.machineId,
|
|
116747
|
+
signal: abort.signal
|
|
116748
|
+
}, (rows) => {
|
|
116749
|
+
if (stopped)
|
|
116750
|
+
return;
|
|
116751
|
+
const changed = agentOperationalReadModel.replace(rows);
|
|
116752
|
+
const snapshots = changed.flatMap(({ chatroomId, role }) => taskSnapshotState.listForRole(chatroomId, role));
|
|
116753
|
+
if (snapshots.length === 0)
|
|
116754
|
+
return;
|
|
116755
|
+
processTasksUpdate(runtime4, effectContext2, cooldown, agentMgr, sessionDeps, session2.machineId, "operational-status", { snapshots: enrichSnapshotsWithOperational(snapshots) }).catch((error51) => console.warn("[TaskInbox] operational-status reconcile failed:", error51));
|
|
116756
|
+
}) ?? (() => {});
|
|
116538
116757
|
const reconcileTimer = setInterval(() => {
|
|
116539
116758
|
if (stopped || inboxUpdateInFlight || reconcileInFlight)
|
|
116540
116759
|
return;
|
|
116541
116760
|
reconcileInFlight = true;
|
|
116542
|
-
processTasksUpdate(runtime4, effectContext2, cooldown, agentMgr, sessionDeps, session2.machineId, "periodic-reconcile", { snapshots: taskSnapshotState.listAll() }).catch((error51) => {
|
|
116761
|
+
processTasksUpdate(runtime4, effectContext2, cooldown, agentMgr, sessionDeps, session2.machineId, "periodic-reconcile", { snapshots: enrichSnapshotsWithOperational(taskSnapshotState.listAll()) }).catch((error51) => {
|
|
116543
116762
|
console.warn("[TaskInbox] local delivery reconciliation failed:", error51);
|
|
116544
116763
|
}).finally(() => {
|
|
116545
116764
|
reconcileInFlight = false;
|
|
@@ -116549,6 +116768,7 @@ var NATIVE_DELIVERY_RECONCILE_MS = 1e4, INBOX_RESTART_INITIAL_MS = 1000, INBOX_R
|
|
|
116549
116768
|
return {
|
|
116550
116769
|
stop() {
|
|
116551
116770
|
stopped = true;
|
|
116771
|
+
unsubscribeOperational();
|
|
116552
116772
|
abort.abort();
|
|
116553
116773
|
clearInterval(reconcileTimer);
|
|
116554
116774
|
unregisterNativeDeliverySession();
|
|
@@ -116563,6 +116783,8 @@ var init_task_inbox_runtime = __esm(() => {
|
|
|
116563
116783
|
init_native_delivery_session_registry();
|
|
116564
116784
|
init_task_delivery_processor();
|
|
116565
116785
|
init_task_delivery_logic();
|
|
116786
|
+
init_enrich_snapshot_with_operational();
|
|
116787
|
+
init_subscribe_machine_agent_operational_status();
|
|
116566
116788
|
init_fetch_machine_assigned_task_snapshots();
|
|
116567
116789
|
init_inbox();
|
|
116568
116790
|
init_task_inbox_delivery();
|
|
@@ -117020,6 +117242,9 @@ function createDaemonRuntime(deps) {
|
|
|
117020
117242
|
shutdownWatchdog.unref?.();
|
|
117021
117243
|
if (heartbeatTimer)
|
|
117022
117244
|
clearInterval(heartbeatTimer);
|
|
117245
|
+
await deps.agentLifecycleOutbox?.stopAll().catch(() => {
|
|
117246
|
+
return;
|
|
117247
|
+
});
|
|
117023
117248
|
stopWorkers();
|
|
117024
117249
|
await withTimeout2(exports_Effect.runPromise(exports_Effect.gen(function* () {
|
|
117025
117250
|
const effectContext2 = yield* exports_Effect.context();
|
|
@@ -132841,7 +133066,11 @@ async function startDaemon() {
|
|
|
132841
133066
|
console.log(`[daemon] Local web UI: http://127.0.0.1:${localWeb.port}/`);
|
|
132842
133067
|
const layers = daemonSessionToLayers(init2);
|
|
132843
133068
|
startBackgroundMachineCapabilitiesDiscovery(createStartBackgroundCapabilitiesDiscoveryDeps(layers));
|
|
132844
|
-
const runtime4 = createDaemonRuntime({
|
|
133069
|
+
const runtime4 = createDaemonRuntime({
|
|
133070
|
+
wsClient: wsClient2,
|
|
133071
|
+
layers,
|
|
133072
|
+
agentLifecycleOutbox: init2.agentLifecycleOutbox
|
|
133073
|
+
});
|
|
132845
133074
|
try {
|
|
132846
133075
|
await runtime4.run();
|
|
132847
133076
|
} finally {
|
|
@@ -134086,4 +134315,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
134086
134315
|
});
|
|
134087
134316
|
program2.parse();
|
|
134088
134317
|
|
|
134089
|
-
//# debugId=
|
|
134318
|
+
//# debugId=6F8892900A69B55764756E2164756E21
|