@link-assistant/hive-mind 1.27.0 → 1.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/README.md +42 -15
- package/package.json +1 -1
- package/src/github-merge.lib.mjs +17 -6
- package/src/solve.accept-invite.lib.mjs +89 -0
- package/src/solve.config.lib.mjs +6 -1
- package/src/solve.mjs +7 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# @link-assistant/hive-mind
|
|
2
2
|
|
|
3
|
+
## 1.29.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 161b595: feat: add --auto-accept-invite option to solve command
|
|
8
|
+
|
|
9
|
+
Adds a new `--auto-accept-invite` boolean option to the `solve` command that automatically accepts the pending GitHub repository or organization invitation for the specific repository/organization being solved, before checking write access.
|
|
10
|
+
|
|
11
|
+
Unlike the `/accept_invites` Telegram command (which accepts ALL pending invitations), this option is scoped to the target repo/org only, making it safer and more targeted. Useful when you've just been invited to a repository and want to run `solve` without manually accepting the invitation first.
|
|
12
|
+
|
|
13
|
+
## 1.28.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- docs: expand best practices with CI/CD guide, universal prompts, and architecture improvement (Issue #1403)
|
|
18
|
+
|
|
19
|
+
Splits the existing `docs/BEST-PRACTICES.md` into two focused documents:
|
|
20
|
+
- **`docs/CI-CD-BEST-PRACTICES.md`** (renamed from the original) — Updated and expanded CI/CD guide covering all key points from existing workflow templates, including: running checks only on relevant file changes, fast-fail job ordering, fresh merge simulation, concurrency control, changeset exemptions for docs-only PRs, secrets detection, documentation validation, and OIDC trusted publishing.
|
|
21
|
+
- **`docs/BEST-PRACTICES.md`** (new general guide) — Universal best practices for AI-driven development including: deep analysis bug/feature prompts, universal validation prompt, plan mode prompt, issue writing guidelines with acceptance criteria patterns, an architecture improvement prompt linking to the Code Architecture Principles repository, CI/CD summary with link to the CI/CD guide, and subagent coordination patterns.
|
|
22
|
+
|
|
23
|
+
Also updates `README.md` to link to both new documents in the Best Practices section.
|
|
24
|
+
|
|
25
|
+
feat: enable --auto-restart-until-mergeable by default (Issue #1360)
|
|
26
|
+
|
|
27
|
+
The `--auto-restart-until-mergeable` feature has become stable enough to be enabled by default. Previously, users had to explicitly pass this flag to enable automatic restart until the PR becomes mergeable.
|
|
28
|
+
|
|
29
|
+
Now the feature is enabled by default, meaning the solver will automatically restart on new comments from non-bot users, CI failures, merge conflicts, or other issues — without requiring any extra flags. Users who want to disable this behavior can pass `--no-auto-restart-until-mergeable`.
|
|
30
|
+
|
|
31
|
+
fix: filter GitHub Pages deployment workflows from PR CI check (Issue #1399)
|
|
32
|
+
|
|
33
|
+
`getActiveRepoWorkflows()` included the `pages-build-deployment` workflow (path: `dynamic/pages/pages-build-deployment`) as if it were a PR CI workflow. This workflow is auto-created by GitHub for GitHub Pages and only runs on the default branch after merge — it never creates check-runs on PR branches. As a result, `--auto-restart-until-mergeable` got stuck in an infinite loop waiting for CI checks that would never appear.
|
|
34
|
+
|
|
35
|
+
The fix filters out workflows with the `dynamic/pages/` prefix from `getActiveRepoWorkflows()`. These are GitHub Pages internal workflows, not user-defined CI pipelines.
|
|
36
|
+
|
|
37
|
+
Affected scenario: repositories with GitHub Pages enabled but no `.github/workflows/` files (e.g., `konard/links-visuals`).
|
|
38
|
+
|
|
39
|
+
fix: resolve Prettier formatting issue in README.md (Issue #1401)
|
|
40
|
+
|
|
41
|
+
The CI/CD `lint` job was failing on the `main` branch because README.md had Prettier formatting violations after commit `da376061` ("Clarify Time Freedom and Any Device Programming features"). That commit added longer text to two table cells, which made the table column widths inconsistent with Prettier's expected format.
|
|
42
|
+
|
|
43
|
+
The fix runs `prettier --write` on README.md to re-align the table column widths, bringing the file back into conformance with the `format:check` CI step.
|
|
44
|
+
|
|
3
45
|
## 1.27.0
|
|
4
46
|
|
|
5
47
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -21,18 +21,18 @@ Inspired by [konard/problem-solving](https://github.com/konard/problem-solving)
|
|
|
21
21
|
|
|
22
22
|
Hive Mind is a **generalist AI** (mini-AGI) capable of working on a wide range of tasks - not just programming. Almost anything that can be done with files in a repository can be automated.
|
|
23
23
|
|
|
24
|
-
| Feature | What It Means For You
|
|
25
|
-
| ---------------------------- |
|
|
26
|
-
| **No Babysitting** | Full autonomous mode with sudo access. AI has creative freedom like a real programmer.
|
|
27
|
-
| **Cloud Isolation** | Runs on dedicated VMs or Docker. Easy to restore if broken.
|
|
28
|
-
| **Full Internet + Sudo** | AI can install packages, fetch docs, and configure the system as needed.
|
|
29
|
-
| **Pre-installed Toolchain** | 25GB+ ready: 10 language runtimes, 2 theorem provers, build tools. Can install more.
|
|
30
|
-
| **Token Efficiency** | Routine tasks automated in code, so AI tokens focus on creative problem-solving.
|
|
31
|
-
| **Time Freedom** | What takes humans 2-8 hours, AI completes in 10-25 minutes. "The code is written while you sleep." |
|
|
32
|
-
| **Scale with Orchestration** | Parallel workers feel like a team of developers, all for ~$200/month.
|
|
33
|
-
| **Human Control** | AI creates draft PRs - you decide what merges. Quality gates where they matter.
|
|
34
|
-
| **Any Device Programming** | Manage AI from any device with `/solve` and `/hive
|
|
35
|
-
| **100% Open Source** | Unlicense (public domain). Full transparency, no vendor lock-in.
|
|
24
|
+
| Feature | What It Means For You |
|
|
25
|
+
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
26
|
+
| **No Babysitting** | Full autonomous mode with sudo access. AI has creative freedom like a real programmer. |
|
|
27
|
+
| **Cloud Isolation** | Runs on dedicated VMs or Docker. Easy to restore if broken. |
|
|
28
|
+
| **Full Internet + Sudo** | AI can install packages, fetch docs, and configure the system as needed. |
|
|
29
|
+
| **Pre-installed Toolchain** | 25GB+ ready: 10 language runtimes, 2 theorem provers, build tools. Can install more. |
|
|
30
|
+
| **Token Efficiency** | Routine tasks automated in code, so AI tokens focus on creative problem-solving. |
|
|
31
|
+
| **Time Freedom** | What takes humans 2-8 hours, AI completes each working session in 10-25 minutes. Mass execution of tasks in repository is possible. "The code is written while you sleep." |
|
|
32
|
+
| **Scale with Orchestration** | Parallel workers feel like a team of developers, all for ~$200/month. |
|
|
33
|
+
| **Human Control** | AI creates draft PRs - you decide what merges. Quality gates where they matter. |
|
|
34
|
+
| **Any Device Programming** | Manage AI from any device with `/solve` and `/hive` via Telegram bot. No PC, IDE, or laptop required. |
|
|
35
|
+
| **100% Open Source** | Unlicense (public domain). Full transparency, no vendor lock-in. |
|
|
36
36
|
|
|
37
37
|
> _"Compared to Codex for $200, this solution is fire."_ - User feedback
|
|
38
38
|
|
|
@@ -404,9 +404,9 @@ The Hive Mind includes a Telegram bot interface (SwarmMindBot) for remote comman
|
|
|
404
404
|
|
|
405
405
|
### 🚀 Test Drive
|
|
406
406
|
|
|
407
|
-
Want to see the Hive Mind in action?
|
|
407
|
+
Want to see the Hive Mind in action? Request a free demo or get faster support by messaging the developer directly on Telegram:
|
|
408
408
|
|
|
409
|
-
**[
|
|
409
|
+
**[Message @drakonard on Telegram](https://t.me/drakonard)**
|
|
410
410
|
|
|
411
411
|
### Setup
|
|
412
412
|
|
|
@@ -839,6 +839,30 @@ screen -wipe
|
|
|
839
839
|
screen -ls
|
|
840
840
|
```
|
|
841
841
|
|
|
842
|
+
### Top with full arguments of each command
|
|
843
|
+
|
|
844
|
+
```bash
|
|
845
|
+
top -c
|
|
846
|
+
```
|
|
847
|
+
|
|
848
|
+
### See the full tree of processes
|
|
849
|
+
|
|
850
|
+
```bash
|
|
851
|
+
ps -eo pid,ppid,user,args --forest
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
or
|
|
855
|
+
|
|
856
|
+
```bash
|
|
857
|
+
ps axjf
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
### Kill all commands spawned by specific task
|
|
861
|
+
|
|
862
|
+
```bash
|
|
863
|
+
pkill -f gh-issue-solver-1773073065743
|
|
864
|
+
```
|
|
865
|
+
|
|
842
866
|
That can be done, but not recommended as reboot have better effect.
|
|
843
867
|
|
|
844
868
|
## 📄 License
|
|
@@ -847,7 +871,10 @@ Unlicense License - see [LICENSE](./LICENSE)
|
|
|
847
871
|
|
|
848
872
|
## 🏆 Best Practices
|
|
849
873
|
|
|
850
|
-
Hive Mind works even better when repositories have strong CI/CD pipelines
|
|
874
|
+
Hive Mind works even better when repositories have strong CI/CD pipelines and clear issue requirements. See:
|
|
875
|
+
|
|
876
|
+
- [BEST-PRACTICES.md](./docs/BEST-PRACTICES.md) — Universal prompts, issue writing guidelines, architecture improvement, and subagent patterns
|
|
877
|
+
- [CI-CD-BEST-PRACTICES.md](./docs/CI-CD-BEST-PRACTICES.md) — CI/CD pipeline setup, recommended templates, and enforcement strategies
|
|
851
878
|
|
|
852
879
|
Key benefits of proper CI/CD:
|
|
853
880
|
|
package/package.json
CHANGED
package/src/github-merge.lib.mjs
CHANGED
|
@@ -1403,20 +1403,31 @@ export async function getWorkflowRunsForSha(owner, repo, sha, verbose = false) {
|
|
|
1403
1403
|
* When a repo has NO workflows, no_checks means no CI configured.
|
|
1404
1404
|
* When a repo HAS workflows, no_checks means CI checks haven't started yet (race condition).
|
|
1405
1405
|
*
|
|
1406
|
+
* Issue #1399: GitHub Pages deployment workflows (path: "dynamic/pages/...") are excluded
|
|
1407
|
+
* because they only run on the default branch after merge, never on PR branches. Counting
|
|
1408
|
+
* them as "CI workflows" causes an infinite loop waiting for check-runs that never appear.
|
|
1409
|
+
*
|
|
1406
1410
|
* @param {string} owner - Repository owner
|
|
1407
1411
|
* @param {string} repo - Repository name
|
|
1408
1412
|
* @param {boolean} verbose - Whether to log verbose output
|
|
1409
|
-
* @returns {Promise<{count: number, hasWorkflows: boolean, workflows: Array<{id: number, name: string, state: string}>}>}
|
|
1413
|
+
* @returns {Promise<{count: number, hasWorkflows: boolean, workflows: Array<{id: number, name: string, state: string, path: string}>}>}
|
|
1410
1414
|
*/
|
|
1411
1415
|
export async function getActiveRepoWorkflows(owner, repo, verbose = false) {
|
|
1412
1416
|
try {
|
|
1413
|
-
const { stdout } = await exec(`gh api "repos/${owner}/${repo}/actions/workflows" --jq '[.workflows[] | select(.state == "active")] | map({id: .id, name: .name, state: .state})'`);
|
|
1414
|
-
const
|
|
1417
|
+
const { stdout } = await exec(`gh api "repos/${owner}/${repo}/actions/workflows" --jq '[.workflows[] | select(.state == "active")] | map({id: .id, name: .name, state: .state, path: .path})'`);
|
|
1418
|
+
const allWorkflows = JSON.parse(stdout.trim() || '[]');
|
|
1419
|
+
|
|
1420
|
+
// Issue #1399: Filter out GitHub Pages deployment workflows.
|
|
1421
|
+
// These have path "dynamic/pages/pages-build-deployment" and only run on the
|
|
1422
|
+
// default branch after merge — they never produce check-runs on PR branches.
|
|
1423
|
+
// Including them causes an infinite loop when waiting for PR CI checks.
|
|
1424
|
+
const workflows = allWorkflows.filter(wf => !wf.path.startsWith('dynamic/pages/'));
|
|
1415
1425
|
|
|
1416
1426
|
if (verbose) {
|
|
1417
|
-
console.log(`[VERBOSE] /merge: Found ${
|
|
1418
|
-
for (const wf of
|
|
1419
|
-
|
|
1427
|
+
console.log(`[VERBOSE] /merge: Found ${allWorkflows.length} active workflows in ${owner}/${repo} (${workflows.length} PR-relevant after filtering out GitHub Pages deployment workflows)`);
|
|
1428
|
+
for (const wf of allWorkflows) {
|
|
1429
|
+
const filtered = wf.path.startsWith('dynamic/pages/');
|
|
1430
|
+
console.log(`[VERBOSE] /merge: - ${wf.name} (${wf.id}): ${wf.state}, path=${wf.path}${filtered ? ' [excluded: GitHub Pages deployment]' : ''}`);
|
|
1420
1431
|
}
|
|
1421
1432
|
}
|
|
1422
1433
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-accept GitHub invitation for a specific repository/organization.
|
|
3
|
+
*
|
|
4
|
+
* Unlike the /accept_invites Telegram command (which accepts ALL pending invitations),
|
|
5
|
+
* this module only accepts the invitation for the specific repository or organization
|
|
6
|
+
* that is being solved. This is safer and more targeted.
|
|
7
|
+
*
|
|
8
|
+
* @see https://docs.github.com/en/rest/collaborators/invitations
|
|
9
|
+
* @see https://docs.github.com/en/rest/orgs/members
|
|
10
|
+
* @see https://github.com/link-assistant/hive-mind/issues/1373
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { promisify } from 'util';
|
|
14
|
+
import { exec as execCallback } from 'child_process';
|
|
15
|
+
|
|
16
|
+
const exec = promisify(execCallback);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Accepts pending GitHub repository or organization invitation for a specific target.
|
|
20
|
+
*
|
|
21
|
+
* Checks for a pending repository invitation matching `owner/repo` and/or a pending
|
|
22
|
+
* organization membership for `owner`. Accepts only the matching invitation(s).
|
|
23
|
+
*
|
|
24
|
+
* @param {string} owner - Repository owner (user or organization login)
|
|
25
|
+
* @param {string} repo - Repository name
|
|
26
|
+
* @param {Function} log - Logging function
|
|
27
|
+
* @param {boolean} verbose - Whether verbose logging is enabled
|
|
28
|
+
* @returns {Promise<{acceptedRepo: boolean, acceptedOrg: boolean}>} Result of acceptance attempts
|
|
29
|
+
*/
|
|
30
|
+
export async function autoAcceptInviteForRepo(owner, repo, log, verbose) {
|
|
31
|
+
const result = { acceptedRepo: false, acceptedOrg: false };
|
|
32
|
+
const fullName = `${owner}/${repo}`;
|
|
33
|
+
|
|
34
|
+
await log(`🔍 --auto-accept-invite: Checking for pending invitation to ${fullName}...`);
|
|
35
|
+
|
|
36
|
+
// Check for pending repository invitation
|
|
37
|
+
try {
|
|
38
|
+
const { stdout: repoInvJson } = await exec('gh api /user/repository_invitations 2>/dev/null || echo "[]"');
|
|
39
|
+
const repoInvitations = JSON.parse(repoInvJson.trim() || '[]');
|
|
40
|
+
verbose && (await log(` Found ${repoInvitations.length} total pending repo invitation(s)`, { verbose: true }));
|
|
41
|
+
|
|
42
|
+
const matchingInv = repoInvitations.find(inv => inv.repository?.full_name?.toLowerCase() === fullName.toLowerCase());
|
|
43
|
+
|
|
44
|
+
if (matchingInv) {
|
|
45
|
+
try {
|
|
46
|
+
await exec(`gh api -X PATCH /user/repository_invitations/${matchingInv.id}`);
|
|
47
|
+
await log(`✅ --auto-accept-invite: Accepted repository invitation for ${fullName}`);
|
|
48
|
+
result.acceptedRepo = true;
|
|
49
|
+
} catch (e) {
|
|
50
|
+
await log(`⚠️ --auto-accept-invite: Failed to accept repository invitation for ${fullName}: ${e.message}`, { level: 'warning' });
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
verbose && (await log(` No pending repository invitation found for ${fullName}`, { verbose: true }));
|
|
54
|
+
}
|
|
55
|
+
} catch (e) {
|
|
56
|
+
verbose && (await log(` Could not fetch repository invitations: ${e.message}`, { verbose: true }));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Check for pending organization membership
|
|
60
|
+
try {
|
|
61
|
+
const { stdout: orgMemJson } = await exec('gh api /user/memberships/orgs 2>/dev/null || echo "[]"');
|
|
62
|
+
const orgMemberships = JSON.parse(orgMemJson.trim() || '[]');
|
|
63
|
+
const pendingOrgs = orgMemberships.filter(m => m.state === 'pending');
|
|
64
|
+
verbose && (await log(` Found ${pendingOrgs.length} total pending org invitation(s)`, { verbose: true }));
|
|
65
|
+
|
|
66
|
+
const matchingOrg = pendingOrgs.find(m => m.organization?.login?.toLowerCase() === owner.toLowerCase());
|
|
67
|
+
|
|
68
|
+
if (matchingOrg) {
|
|
69
|
+
const orgName = matchingOrg.organization.login;
|
|
70
|
+
try {
|
|
71
|
+
await exec(`gh api -X PATCH /user/memberships/orgs/${orgName} -f state=active`);
|
|
72
|
+
await log(`✅ --auto-accept-invite: Accepted organization invitation for ${orgName}`);
|
|
73
|
+
result.acceptedOrg = true;
|
|
74
|
+
} catch (e) {
|
|
75
|
+
await log(`⚠️ --auto-accept-invite: Failed to accept organization invitation for ${orgName}: ${e.message}`, { level: 'warning' });
|
|
76
|
+
}
|
|
77
|
+
} else {
|
|
78
|
+
verbose && (await log(` No pending organization invitation found for ${owner}`, { verbose: true }));
|
|
79
|
+
}
|
|
80
|
+
} catch (e) {
|
|
81
|
+
verbose && (await log(` Could not fetch organization memberships: ${e.message}`, { verbose: true }));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (!result.acceptedRepo && !result.acceptedOrg) {
|
|
85
|
+
await log(`ℹ️ --auto-accept-invite: No pending invitation found for ${fullName} or organization ${owner}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return result;
|
|
89
|
+
}
|
package/src/solve.config.lib.mjs
CHANGED
|
@@ -179,7 +179,7 @@ export const SOLVE_OPTION_DEFINITIONS = {
|
|
|
179
179
|
'auto-restart-until-mergeable': {
|
|
180
180
|
type: 'boolean',
|
|
181
181
|
description: 'Auto-restart until PR becomes mergeable (no iteration limit). Restarts on new comments from non-bot users, CI failures, merge conflicts, or other issues. Does NOT auto-merge.',
|
|
182
|
-
default:
|
|
182
|
+
default: true,
|
|
183
183
|
},
|
|
184
184
|
'auto-restart-on-non-updated-pull-request-description': {
|
|
185
185
|
type: 'boolean',
|
|
@@ -369,6 +369,11 @@ export const SOLVE_OPTION_DEFINITIONS = {
|
|
|
369
369
|
description: 'Automatically attach solution summary only if the AI did not create any comments during the session. This provides visible feedback when the AI completes silently.',
|
|
370
370
|
default: false,
|
|
371
371
|
},
|
|
372
|
+
'auto-accept-invite': {
|
|
373
|
+
type: 'boolean',
|
|
374
|
+
description: 'Automatically accept the pending GitHub repository or organization invitation for the specific repository/organization being solved, before checking write access. Unlike /accept_invites which accepts all pending invitations, this only accepts the invite for the target repo/org.',
|
|
375
|
+
default: false,
|
|
376
|
+
},
|
|
372
377
|
};
|
|
373
378
|
|
|
374
379
|
// Function to create yargs configuration - avoids duplication
|
package/src/solve.mjs
CHANGED
|
@@ -94,6 +94,8 @@ const { prepareFeedbackAndTimestamps, checkUncommittedChanges, checkForkActions
|
|
|
94
94
|
// Import model validation library
|
|
95
95
|
const modelValidation = await import('./model-validation.lib.mjs');
|
|
96
96
|
const { validateAndExitOnInvalidModel } = modelValidation;
|
|
97
|
+
const acceptInviteLib = await import('./solve.accept-invite.lib.mjs');
|
|
98
|
+
const { autoAcceptInviteForRepo } = acceptInviteLib;
|
|
97
99
|
|
|
98
100
|
// Initialize log file EARLY to capture all output including version and command
|
|
99
101
|
// Use default directory (cwd) initially, will be set from argv.logDir after parsing
|
|
@@ -313,6 +315,11 @@ if (argv.autoFork && !argv.fork) {
|
|
|
313
315
|
}
|
|
314
316
|
}
|
|
315
317
|
|
|
318
|
+
// Accept pending GitHub invitation for the specific repo/org before checking write access
|
|
319
|
+
if (argv.autoAcceptInvite) {
|
|
320
|
+
await autoAcceptInviteForRepo(owner, repo, log, argv.verbose);
|
|
321
|
+
}
|
|
322
|
+
|
|
316
323
|
// Early check: Verify repository write permissions BEFORE doing any work
|
|
317
324
|
// This prevents wasting AI tokens when user doesn't have access and --fork is not used
|
|
318
325
|
const { checkRepositoryWritePermission } = githubLib;
|