@mizyoel/mercury-mesh 0.9.4
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/.copilot/mcp-config.json +14 -0
- package/.copilot/skills/agent-collaboration/SKILL.md +42 -0
- package/.copilot/skills/agent-conduct/SKILL.md +24 -0
- package/.copilot/skills/architectural-proposals/SKILL.md +151 -0
- package/.copilot/skills/ci-validation-gates/SKILL.md +84 -0
- package/.copilot/skills/cli-wiring/SKILL.md +47 -0
- package/.copilot/skills/client-compatibility/SKILL.md +89 -0
- package/.copilot/skills/cross-mesh/SKILL.md +114 -0
- package/.copilot/skills/distributed-mesh/SKILL.md +287 -0
- package/.copilot/skills/distributed-mesh/mesh.json.example +30 -0
- package/.copilot/skills/distributed-mesh/sync-mesh.ps1 +111 -0
- package/.copilot/skills/distributed-mesh/sync-mesh.sh +104 -0
- package/.copilot/skills/docs-standards/SKILL.md +71 -0
- package/.copilot/skills/economy-mode/SKILL.md +101 -0
- package/.copilot/skills/external-comms/SKILL.md +331 -0
- package/.copilot/skills/gh-auth-isolation/SKILL.md +183 -0
- package/.copilot/skills/git-workflow/SKILL.md +206 -0
- package/.copilot/skills/github-multi-account/SKILL.md +95 -0
- package/.copilot/skills/history-hygiene/SKILL.md +36 -0
- package/.copilot/skills/humanizer/SKILL.md +107 -0
- package/.copilot/skills/init-mode/SKILL.md +101 -0
- package/.copilot/skills/mesh-conventions/SKILL.md +69 -0
- package/.copilot/skills/model-selection/SKILL.md +139 -0
- package/.copilot/skills/nap/SKILL.md +24 -0
- package/.copilot/skills/personal-mesh/SKILL.md +57 -0
- package/.copilot/skills/project-conventions/SKILL.md +56 -0
- package/.copilot/skills/release-process/SKILL.md +435 -0
- package/.copilot/skills/reskill/SKILL.md +92 -0
- package/.copilot/skills/reviewer-protocol/SKILL.md +79 -0
- package/.copilot/skills/secret-handling/SKILL.md +200 -0
- package/.copilot/skills/session-recovery/SKILL.md +155 -0
- package/.copilot/skills/test-discipline/SKILL.md +37 -0
- package/.copilot/skills/windows-compatibility/SKILL.md +74 -0
- package/.github/agents/mercury-mesh.agent.md +1732 -0
- package/.mesh/manifesto.md +66 -0
- package/.mesh/templates/casting/Futurama.json +10 -0
- package/.mesh/templates/casting-history.json +4 -0
- package/.mesh/templates/casting-policy.json +37 -0
- package/.mesh/templates/casting-reference.md +104 -0
- package/.mesh/templates/casting-registry.json +3 -0
- package/.mesh/templates/ceremonies.md +41 -0
- package/.mesh/templates/charter.md +56 -0
- package/.mesh/templates/constraint-tracking.md +38 -0
- package/.mesh/templates/cooperative-rate-limiting.md +229 -0
- package/.mesh/templates/copilot-instructions.md +50 -0
- package/.mesh/templates/department-backlog.md +15 -0
- package/.mesh/templates/department-charter.md +27 -0
- package/.mesh/templates/department-state.json +19 -0
- package/.mesh/templates/history.md +10 -0
- package/.mesh/templates/identity/now.md +9 -0
- package/.mesh/templates/identity/wisdom.md +15 -0
- package/.mesh/templates/interface-contract.md +26 -0
- package/.mesh/templates/issue-lifecycle.md +421 -0
- package/.mesh/templates/keda-scaler.md +166 -0
- package/.mesh/templates/machine-capabilities.md +77 -0
- package/.mesh/templates/mcp-config.md +90 -0
- package/.mesh/templates/mercury-mesh.agent.md +1732 -0
- package/.mesh/templates/multi-agent-format.md +28 -0
- package/.mesh/templates/orchestration-log.md +27 -0
- package/.mesh/templates/org-autonomy-spec.md +152 -0
- package/.mesh/templates/org-backlog-from-triage.js +199 -0
- package/.mesh/templates/org-runtime-reconcile.js +364 -0
- package/.mesh/templates/org-seed-runtime.js +238 -0
- package/.mesh/templates/org-status.js +193 -0
- package/.mesh/templates/org-structure.json +38 -0
- package/.mesh/templates/package.json +3 -0
- package/.mesh/templates/plugin-marketplace.md +49 -0
- package/.mesh/templates/ralph-circuit-breaker.md +313 -0
- package/.mesh/templates/ralph-triage.js +844 -0
- package/.mesh/templates/raw-agent-output.md +37 -0
- package/.mesh/templates/roster.md +60 -0
- package/.mesh/templates/routing.md +78 -0
- package/.mesh/templates/run-output.md +50 -0
- package/.mesh/templates/schedule.json +64 -0
- package/.mesh/templates/scribe-charter.md +119 -0
- package/.mesh/templates/skill.md +24 -0
- package/.mesh/templates/skills/agent-collaboration/SKILL.md +42 -0
- package/.mesh/templates/skills/agent-conduct/SKILL.md +24 -0
- package/.mesh/templates/skills/architectural-proposals/SKILL.md +151 -0
- package/.mesh/templates/skills/ci-validation-gates/SKILL.md +84 -0
- package/.mesh/templates/skills/cli-wiring/SKILL.md +47 -0
- package/.mesh/templates/skills/client-compatibility/SKILL.md +89 -0
- package/.mesh/templates/skills/cross-mesh/SKILL.md +114 -0
- package/.mesh/templates/skills/distributed-mesh/SKILL.md +287 -0
- package/.mesh/templates/skills/distributed-mesh/mesh.json.example +30 -0
- package/.mesh/templates/skills/distributed-mesh/sync-mesh.ps1 +111 -0
- package/.mesh/templates/skills/distributed-mesh/sync-mesh.sh +104 -0
- package/.mesh/templates/skills/docs-standards/SKILL.md +71 -0
- package/.mesh/templates/skills/economy-mode/SKILL.md +101 -0
- package/.mesh/templates/skills/external-comms/SKILL.md +331 -0
- package/.mesh/templates/skills/gh-auth-isolation/SKILL.md +183 -0
- package/.mesh/templates/skills/git-workflow/SKILL.md +204 -0
- package/.mesh/templates/skills/github-multi-account/SKILL.md +95 -0
- package/.mesh/templates/skills/history-hygiene/SKILL.md +36 -0
- package/.mesh/templates/skills/humanizer/SKILL.md +107 -0
- package/.mesh/templates/skills/init-mode/SKILL.md +101 -0
- package/.mesh/templates/skills/mesh-conventions/SKILL.md +69 -0
- package/.mesh/templates/skills/model-selection/SKILL.md +139 -0
- package/.mesh/templates/skills/nap/SKILL.md +24 -0
- package/.mesh/templates/skills/personal-mesh/SKILL.md +57 -0
- package/.mesh/templates/skills/project-conventions/SKILL.md +56 -0
- package/.mesh/templates/skills/release-process/SKILL.md +435 -0
- package/.mesh/templates/skills/reskill/SKILL.md +92 -0
- package/.mesh/templates/skills/reviewer-protocol/SKILL.md +79 -0
- package/.mesh/templates/skills/secret-handling/SKILL.md +200 -0
- package/.mesh/templates/skills/session-recovery/SKILL.md +155 -0
- package/.mesh/templates/skills/test-discipline/SKILL.md +37 -0
- package/.mesh/templates/skills/windows-compatibility/SKILL.md +74 -0
- package/.mesh/templates/workflows/mesh-ci.yml +24 -0
- package/.mesh/templates/workflows/mesh-docs.yml +54 -0
- package/.mesh/templates/workflows/mesh-heartbeat.yml +237 -0
- package/.mesh/templates/workflows/mesh-insider-release.yml +61 -0
- package/.mesh/templates/workflows/mesh-issue-assign.yml +243 -0
- package/.mesh/templates/workflows/mesh-label-enforce.yml +181 -0
- package/.mesh/templates/workflows/mesh-preview.yml +55 -0
- package/.mesh/templates/workflows/mesh-promote.yml +120 -0
- package/.mesh/templates/workflows/mesh-release.yml +77 -0
- package/.mesh/templates/workflows/mesh-triage.yml +383 -0
- package/.mesh/templates/workflows/sync-mesh-labels.yml +204 -0
- package/README.md +640 -0
- package/bin/mercury-mesh.cjs +317 -0
- package/docs/brand-language.md +287 -0
- package/docs/commander-onboarding.md +462 -0
- package/docs/mercury-mesh-runtime-rename-impact.md +148 -0
- package/docs/persona-manifesto.md +114 -0
- package/docs/scenarios/client-compatibility.md +59 -0
- package/index.cjs +41 -0
- package/package.json +43 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Multi-Agent Artifact Format
|
|
2
|
+
|
|
3
|
+
When multiple agents contribute to a final artifact (document, analysis, design), use this format. The assembled result must include:
|
|
4
|
+
|
|
5
|
+
- Termination condition
|
|
6
|
+
- Constraint budgets (if active)
|
|
7
|
+
- Reviewer verdicts (if any)
|
|
8
|
+
- Raw agent outputs appendix
|
|
9
|
+
|
|
10
|
+
## Assembly Structure
|
|
11
|
+
|
|
12
|
+
The assembled result goes at the top. Below it, include:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
## APPENDIX: RAW AGENT OUTPUTS
|
|
16
|
+
|
|
17
|
+
### {Name} ({Role}) — Raw Output
|
|
18
|
+
{Paste agent's verbatim response here, unedited}
|
|
19
|
+
|
|
20
|
+
### {Name} ({Role}) — Raw Output
|
|
21
|
+
{Paste agent's verbatim response here, unedited}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Appendix Rules
|
|
25
|
+
|
|
26
|
+
This appendix is for diagnostic integrity. Do not edit, summarize, or polish the raw outputs. The Coordinator may not rewrite raw agent outputs; it may only paste them verbatim and assemble the final artifact above.
|
|
27
|
+
|
|
28
|
+
See `.mesh/templates/run-output.md` for the complete output format template.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Orchestration Log Entry
|
|
2
|
+
|
|
3
|
+
> One file per agent spawn. Saved to `.mesh/orchestration-log/{timestamp}-{agent-name}.md`
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
### {timestamp} — {task summary}
|
|
8
|
+
|
|
9
|
+
| Field | Value |
|
|
10
|
+
|-------|-------|
|
|
11
|
+
| **Agent routed** | {Name} ({Role}) |
|
|
12
|
+
| **Why chosen** | {Routing rationale — what in the request matched this agent} |
|
|
13
|
+
| **Mode** | {`background` / `sync`} |
|
|
14
|
+
| **Why this mode** | {Brief reason — e.g., "No hard data dependencies" or "User needs to approve architecture"} |
|
|
15
|
+
| **Files authorized to read** | {Exact file paths the agent was told to read} |
|
|
16
|
+
| **File(s) agent must produce** | {Exact file paths the agent is expected to create or modify} |
|
|
17
|
+
| **Outcome** | {Completed / Rejected by {Reviewer} / Escalated} |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Rules
|
|
22
|
+
|
|
23
|
+
1. **One file per agent spawn.** Named `{timestamp}-{agent-name}.md`.
|
|
24
|
+
2. **Log BEFORE spawning.** The entry must exist before the agent runs.
|
|
25
|
+
3. **Update outcome AFTER the agent completes.** Fill in the Outcome field.
|
|
26
|
+
4. **Never delete or edit past entries.** Append-only.
|
|
27
|
+
5. **If a reviewer rejects work,** log the rejection as a new entry with the revision agent.
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Org Autonomy Runtime Spec
|
|
2
|
+
|
|
3
|
+
This spec defines the first minimal runtime for concurrent, semi-autonomous departments in Org Mode.
|
|
4
|
+
|
|
5
|
+
## Design Goal
|
|
6
|
+
|
|
7
|
+
Departments should work concurrently and with local initiative, while remaining inside Mercury Mesh's coordinator-led control plane.
|
|
8
|
+
|
|
9
|
+
The coordinator remains the global control plane.
|
|
10
|
+
Department leads act as local schedulers inside an approved authority envelope.
|
|
11
|
+
Department members execute leased work packets in parallel.
|
|
12
|
+
|
|
13
|
+
## Core Principle
|
|
14
|
+
|
|
15
|
+
**Autonomy is delegated, not sovereign.**
|
|
16
|
+
|
|
17
|
+
- The coordinator still owns spawning, synthesis, and escalation.
|
|
18
|
+
- Department leads may decompose and prioritize local work.
|
|
19
|
+
- Members may claim queued work only within department scope.
|
|
20
|
+
- Human tiers, E-Stop, and lifecycle status always override department autonomy.
|
|
21
|
+
|
|
22
|
+
## Required Runtime Files
|
|
23
|
+
|
|
24
|
+
When `orgMode: true`, create:
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
.mesh/org/
|
|
28
|
+
structure.json
|
|
29
|
+
contracts/
|
|
30
|
+
{contract-name}.md
|
|
31
|
+
{department-id}/
|
|
32
|
+
charter.md
|
|
33
|
+
backlog.md
|
|
34
|
+
state.json
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## structure.json Schema
|
|
38
|
+
|
|
39
|
+
Each department entry should include:
|
|
40
|
+
|
|
41
|
+
- `id`
|
|
42
|
+
- `name`
|
|
43
|
+
- `lead`
|
|
44
|
+
- `members`
|
|
45
|
+
- `domain`
|
|
46
|
+
- `routingKeywords`
|
|
47
|
+
- `leadStyle`
|
|
48
|
+
- `authority.canDecideLocally`
|
|
49
|
+
- `authority.mustEscalate`
|
|
50
|
+
- `runtime.autonomyMode`
|
|
51
|
+
- `runtime.maxParallelism`
|
|
52
|
+
- `runtime.claimLeaseMinutes`
|
|
53
|
+
- `runtime.heartbeatMinutes`
|
|
54
|
+
- `runtime.backlogPath`
|
|
55
|
+
- `runtime.statePath`
|
|
56
|
+
- `runtime.contracts`
|
|
57
|
+
|
|
58
|
+
## Work Item Lifecycle
|
|
59
|
+
|
|
60
|
+
Every backlog item moves through these states:
|
|
61
|
+
|
|
62
|
+
1. `queued`
|
|
63
|
+
2. `claimed`
|
|
64
|
+
3. `in_progress`
|
|
65
|
+
4. `blocked`
|
|
66
|
+
5. `review`
|
|
67
|
+
6. `done`
|
|
68
|
+
|
|
69
|
+
Each claimed item must record:
|
|
70
|
+
|
|
71
|
+
- `workItemId`
|
|
72
|
+
- `claimedBy`
|
|
73
|
+
- `claimedAt`
|
|
74
|
+
- `leaseExpiresAt`
|
|
75
|
+
- `status`
|
|
76
|
+
- `dependsOn`
|
|
77
|
+
- `outputs`
|
|
78
|
+
|
|
79
|
+
## Claim And Lease Protocol
|
|
80
|
+
|
|
81
|
+
- A member may claim only work that is in its department domain and not already claimed.
|
|
82
|
+
- Claims expire after `claimLeaseMinutes`.
|
|
83
|
+
- Expired claims are re-queued by Ralph or the coordinator if `requeueExpiredClaims` is true.
|
|
84
|
+
- Members must heartbeat before lease expiry when long-running work is still active.
|
|
85
|
+
- Shadow agents may inspect backlog items but may not claim execution work.
|
|
86
|
+
|
|
87
|
+
## Department Scheduler Loop
|
|
88
|
+
|
|
89
|
+
The minimal autonomous loop is:
|
|
90
|
+
|
|
91
|
+
1. Coordinator routes a mission to the relevant department lead.
|
|
92
|
+
2. Lead decomposes it into work packets and writes them to `backlog.md`.
|
|
93
|
+
3. Coordinator spawns eligible members against independent packets.
|
|
94
|
+
4. Members execute in parallel under lease.
|
|
95
|
+
5. Lead reviews probationary or blocked outputs.
|
|
96
|
+
6. Scribe records outcomes; Ralph requeues stale work.
|
|
97
|
+
|
|
98
|
+
This preserves the coordinator's spawn ownership while allowing local department initiative.
|
|
99
|
+
|
|
100
|
+
## Cross-Department Work
|
|
101
|
+
|
|
102
|
+
Cross-department work is **contract-first**.
|
|
103
|
+
|
|
104
|
+
- Before departments run in parallel, define an interface contract in `.mesh/org/contracts/`.
|
|
105
|
+
- Contracts define producer, consumer, inputs, outputs, invariants, and version.
|
|
106
|
+
- Departments may proceed concurrently against the current contract version.
|
|
107
|
+
- Contract changes trigger a lead alignment round.
|
|
108
|
+
|
|
109
|
+
## Local Authority
|
|
110
|
+
|
|
111
|
+
Department leads may decide locally on:
|
|
112
|
+
|
|
113
|
+
- internal decomposition
|
|
114
|
+
- packet assignment
|
|
115
|
+
- implementation conventions inside the department
|
|
116
|
+
- test strategy inside the department
|
|
117
|
+
|
|
118
|
+
Department leads must escalate:
|
|
119
|
+
|
|
120
|
+
- architecture changes affecting another department
|
|
121
|
+
- contract changes
|
|
122
|
+
- compute policy exceptions
|
|
123
|
+
- roster changes
|
|
124
|
+
- destructive actions outside department scope
|
|
125
|
+
|
|
126
|
+
## Safety Gates
|
|
127
|
+
|
|
128
|
+
Autonomy is suspended when:
|
|
129
|
+
|
|
130
|
+
- `halted: true`
|
|
131
|
+
- `.mesh/HALT` exists
|
|
132
|
+
- the user lacks required human tier
|
|
133
|
+
- the acting agent is `shadow`
|
|
134
|
+
- department parallelism limit is reached
|
|
135
|
+
- required contract or dependency is unresolved
|
|
136
|
+
|
|
137
|
+
## Minimal Rollout
|
|
138
|
+
|
|
139
|
+
Phase 1 in this repo implements:
|
|
140
|
+
|
|
141
|
+
- org runtime config defaults
|
|
142
|
+
- a structure template with runtime fields
|
|
143
|
+
- department backlog and state templates
|
|
144
|
+
- contract template
|
|
145
|
+
- coordinator rules for delegated department scheduling
|
|
146
|
+
|
|
147
|
+
Future phases can add:
|
|
148
|
+
|
|
149
|
+
- automated claim reconciliation
|
|
150
|
+
- department heartbeats
|
|
151
|
+
- Ralph-driven backlog pickup cycles
|
|
152
|
+
- metrics and compute budgeting per department
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
|
|
7
|
+
const RUNTIME_DIR_CANDIDATES = ['.mesh', '.mercury'];
|
|
8
|
+
|
|
9
|
+
function defaultRuntimeDir() {
|
|
10
|
+
return RUNTIME_DIR_CANDIDATES.find((candidate) => fs.existsSync(candidate)) || '.mesh';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function runtimeDirName(runtimeDir) {
|
|
14
|
+
return path.basename(path.resolve(runtimeDir));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function parseArgs(argv) {
|
|
18
|
+
const options = {
|
|
19
|
+
meshDir: defaultRuntimeDir(),
|
|
20
|
+
triageFile: 'triage-results.json',
|
|
21
|
+
output: 'org-backlog-results.json',
|
|
22
|
+
apply: false,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
26
|
+
const arg = argv[index];
|
|
27
|
+
if (arg === '--mesh-dir') {
|
|
28
|
+
options.meshDir = argv[index + 1];
|
|
29
|
+
index += 1;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (arg === '--triage-file') {
|
|
33
|
+
options.triageFile = argv[index + 1];
|
|
34
|
+
index += 1;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (arg === '--output') {
|
|
38
|
+
options.output = argv[index + 1];
|
|
39
|
+
index += 1;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (arg === '--apply') {
|
|
43
|
+
options.apply = true;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (arg === '--help' || arg === '-h') {
|
|
47
|
+
printUsage();
|
|
48
|
+
process.exit(0);
|
|
49
|
+
}
|
|
50
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return options;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function printUsage() {
|
|
57
|
+
console.log('Usage: node <runtime>/org/backlog-from-triage.js [--mesh-dir .mesh] --triage-file triage-results.json --output org-backlog-results.json [--apply]');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function readJson(filePath) {
|
|
61
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function writeJson(filePath, value) {
|
|
65
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
66
|
+
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function parseMarkdownTable(content) {
|
|
70
|
+
const lines = content.split(/\r?\n/);
|
|
71
|
+
const rows = [];
|
|
72
|
+
|
|
73
|
+
for (const line of lines) {
|
|
74
|
+
const trimmed = line.trim();
|
|
75
|
+
if (!trimmed.startsWith('|') || !trimmed.endsWith('|')) continue;
|
|
76
|
+
const cells = trimmed.slice(1, -1).split('|').map((cell) => cell.trim());
|
|
77
|
+
if (cells.every((cell) => /^-+$/.test(cell))) continue;
|
|
78
|
+
rows.push(cells);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (rows.length < 2) return null;
|
|
82
|
+
return { headers: rows[0], rows: rows.slice(1) };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function locateBacklogTable(lines) {
|
|
86
|
+
let start = -1;
|
|
87
|
+
let end = lines.length;
|
|
88
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
89
|
+
const line = lines[index].trim();
|
|
90
|
+
if (start === -1 && line.startsWith('| ID |')) {
|
|
91
|
+
start = index;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (start !== -1 && line !== '' && !line.startsWith('|')) {
|
|
95
|
+
end = index;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return start === -1 ? null : { start, end };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function serializeMarkdownTable(headers, rows) {
|
|
103
|
+
return [
|
|
104
|
+
`| ${headers.join(' | ')} |`,
|
|
105
|
+
`| ${headers.map(() => '---').join(' | ')} |`,
|
|
106
|
+
...rows.map((row) => `| ${row.join(' | ')} |`),
|
|
107
|
+
];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function updateBacklogFile(backlogPath, addRows, apply) {
|
|
111
|
+
const existing = fs.readFileSync(backlogPath, 'utf8');
|
|
112
|
+
const lines = existing.split(/\r?\n/);
|
|
113
|
+
const table = parseMarkdownTable(existing);
|
|
114
|
+
const tableIndex = locateBacklogTable(lines);
|
|
115
|
+
|
|
116
|
+
if (!table || !tableIndex) {
|
|
117
|
+
throw new Error(`Backlog table not found in ${backlogPath}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const headers = table.headers;
|
|
121
|
+
const updatedRows = [...table.rows, ...addRows];
|
|
122
|
+
const renderedTable = serializeMarkdownTable(headers, updatedRows);
|
|
123
|
+
const nextLines = [...lines];
|
|
124
|
+
nextLines.splice(tableIndex.start, tableIndex.end - tableIndex.start, ...renderedTable);
|
|
125
|
+
|
|
126
|
+
if (apply) {
|
|
127
|
+
fs.writeFileSync(backlogPath, `${nextLines.join('\n')}\n`, 'utf8');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function main() {
|
|
132
|
+
const options = parseArgs(process.argv.slice(2));
|
|
133
|
+
const meshDir = path.resolve(options.meshDir);
|
|
134
|
+
const runtimeName = runtimeDirName(meshDir);
|
|
135
|
+
const repoRoot = path.dirname(meshDir);
|
|
136
|
+
const configPath = path.join(meshDir, 'config.json');
|
|
137
|
+
const structurePath = path.join(meshDir, 'org', 'structure.json');
|
|
138
|
+
const triagePath = path.resolve(options.triageFile);
|
|
139
|
+
|
|
140
|
+
if (!fs.existsSync(configPath)) throw new Error(`config.json not found: ${configPath}`);
|
|
141
|
+
if (!fs.existsSync(structurePath)) throw new Error(`structure.json not found: ${structurePath}`);
|
|
142
|
+
if (!fs.existsSync(triagePath)) throw new Error(`triage file not found: ${triagePath}`);
|
|
143
|
+
|
|
144
|
+
const config = readJson(configPath);
|
|
145
|
+
if (!config.orgMode) {
|
|
146
|
+
writeJson(path.resolve(options.output), { enabled: false, reason: 'orgMode disabled', created: [] });
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const structure = readJson(structurePath);
|
|
151
|
+
const triageResults = readJson(triagePath);
|
|
152
|
+
const departments = new Map((structure.departments || []).map((department) => [department.id, department]));
|
|
153
|
+
const report = { enabled: true, apply: options.apply, generatedAt: new Date().toISOString(), created: [], skipped: [], warnings: [] };
|
|
154
|
+
const rowsByBacklog = new Map();
|
|
155
|
+
|
|
156
|
+
for (const item of triageResults) {
|
|
157
|
+
if (!item.departmentId) {
|
|
158
|
+
report.skipped.push({ issueNumber: item.issueNumber, reason: 'No department assigned' });
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const department = departments.get(item.departmentId);
|
|
163
|
+
if (!department) {
|
|
164
|
+
report.warnings.push(`Unknown department: ${item.departmentId} for issue #${item.issueNumber}`);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const runtime = department.runtime || {};
|
|
169
|
+
const backlogPath = path.resolve(repoRoot, runtime.backlogPath || `${runtimeName}/org/${department.id}/backlog.md`);
|
|
170
|
+
if (!fs.existsSync(backlogPath)) {
|
|
171
|
+
report.warnings.push(`Backlog missing for department ${department.id}: ${path.relative(repoRoot, backlogPath)}`);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const packetId = `${department.id}-issue-${item.issueNumber}`;
|
|
176
|
+
const existing = fs.readFileSync(backlogPath, 'utf8');
|
|
177
|
+
if (existing.includes(`| ${packetId} |`)) {
|
|
178
|
+
report.skipped.push({ issueNumber: item.issueNumber, reason: `Packet already exists in ${path.relative(repoRoot, backlogPath)}` });
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const title = (item.issueTitle || `Issue #${item.issueNumber}`).replace(/\|/g, '/');
|
|
183
|
+
const assignedTo = item.assignTo || 'unassigned';
|
|
184
|
+
const notes = [`Issue #${item.issueNumber}`, `Routed to ${assignedTo}`, item.source ? `source:${item.source}` : null].filter(Boolean).join('; ');
|
|
185
|
+
const row = [packetId, `[Issue #${item.issueNumber}] ${title}`, 'queued', 'unassigned', '-', '-', '-', notes];
|
|
186
|
+
|
|
187
|
+
if (!rowsByBacklog.has(backlogPath)) rowsByBacklog.set(backlogPath, []);
|
|
188
|
+
rowsByBacklog.get(backlogPath).push(row);
|
|
189
|
+
report.created.push({ issueNumber: item.issueNumber, backlogPath: path.relative(repoRoot, backlogPath), packetId, departmentId: item.departmentId });
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
for (const [backlogPath, rows] of rowsByBacklog.entries()) {
|
|
193
|
+
updateBacklogFile(backlogPath, rows, options.apply);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
writeJson(path.resolve(options.output), report);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
main();
|