mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-31 22:14:25 +01:00
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
688f0729f5
commit
f2ddc495dd
7 files changed
+58
-9
No files matched your search
@@ -1,5 +1,19 @@
|
||||
# Changelog
|
||||
|
||||
## [1.91.200.0] - 2026-10-25
|
||||
|
||||
**/cso doctor no longer calls a Go repository "stack: python".** A repository with a root `go.mod` and no Node, Bun, Rails or JVM build matched no supported stack, so preparation fell back to Python and doctor reported `stack: python` with `MISSING_METADATA requirements.txt`, which sent Go users looking for a Python file they never needed (#3263). Go runtime support itself is not planned for now (Garry, 2026-10-24), so /cso keeps running static assessment on Go repositories; the runtime catalog and the /cso release contract are unchanged.
|
||||
|
||||
### Fixed
|
||||
- **`lib/cso/preparation.ts`**: a root `go.mod` with no other supported stack is reported as `stack: go` with `UNSUPPORTED_STACK` ("Go (go.mod) is not a supported runtime stack yet; supported runtime stacks are Node, Bun, Python, and Rails."), the way a Maven or Gradle build is already reported as Java. Python helper metadata beside `go.mod` (a docs `requirements.txt`, say) no longer turns the repository into Python. A `go.mod` beside a Node, Bun or Rails lockfile leaves that stack's detection as it was.
|
||||
|
||||
### Tests
|
||||
- `test/cso-preparation.test.ts` checks that a Go module is `go` with exactly that prerequisite and never mentions `requirements.txt`, and that a hashed `requirements.txt` beside `go.mod` stays Go. Both fail on main. Controls: `go.mod` beside a Node lockfile stays a ready Node plan, a Python project without `go.mod` stays Python, and a repository with no stack metadata keeps the Python fallback.
|
||||
- `test/helpers/cso-runtime-catalog.ts` leaves `go` out of its qualified-runtime fixture list, as it already did `java`.
|
||||
|
||||
### Gate integrity
|
||||
- No gate edit. No threshold, budget, timeout, trial count or case kind changed.
|
||||
|
||||
## [1.91.199.0] - 2026-10-25
|
||||
|
||||
**When /sync-gbrain refuses because a gbrain autopilot is running, it now says which process it found and what to do.** The guard against syncing while `gbrain autopilot` runs is machine-wide on purpose: two syncs sharing one brain or working tree can race and delete files (#1734). But the refusal only said `(process:gbrain autopilot)`, so someone whose autopilot served a different brain could not tell what was blocking them (#3360, part 1). Garry decided on 2026-10-24 to keep the check machine-wide and improve the message.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# gstack digest v1.91.199.0 — regenerate/re-copy after upgrading gstack
|
||||
# gstack digest v1.91.200.0 — regenerate/re-copy after upgrading gstack
|
||||
|
||||
Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed
|
||||
for agent hosts without a full skill install. The full skills add workflows,
|
||||
|
||||
+14
-5
@@ -5,8 +5,8 @@ import { createHash } from 'node:crypto';
|
||||
import { lstatSync, readFileSync, realpathSync } from 'node:fs';
|
||||
import { isAbsolute, relative, resolve, sep } from 'node:path';
|
||||
|
||||
/** 'java' (Maven or Gradle) is detected so it is reported as itself; no runtime prepares it. */
|
||||
export type CsoStack = 'node' | 'bun' | 'python' | 'rails' | 'java';
|
||||
/** 'java' (Maven or Gradle) and 'go' (go.mod) are detected so they are reported as themselves; no runtime prepares them. */
|
||||
export type CsoStack = 'node' | 'bun' | 'python' | 'rails' | 'java' | 'go';
|
||||
export interface PreparationPrerequisite {
|
||||
code: string;
|
||||
message: string;
|
||||
@@ -1205,12 +1205,15 @@ export function inspectPreparation(snapshotPath: string, stack?: CsoStack): Prep
|
||||
detectedStacks.push('node');
|
||||
if (read(root, 'Gemfile.lock', true) !== undefined || read(root, 'Gemfile', true) !== undefined)
|
||||
detectedStacks.push('rails');
|
||||
// A root Maven or Gradle build names the repository's language; Python
|
||||
// metadata beside it is helper tooling, not a second application stack.
|
||||
// A root Maven or Gradle build, or a root go.mod with no other supported
|
||||
// stack, names the repository's language; Python metadata beside it is
|
||||
// helper tooling, not a second application stack.
|
||||
const jvmBuild = ['pom.xml', 'build.gradle', 'build.gradle.kts'].find(
|
||||
(file) => read(root, file, true) !== undefined,
|
||||
);
|
||||
if (jvmBuild) detectedStacks.push('java');
|
||||
else if (detectedStacks.length === 0 && read(root, 'go.mod', true) !== undefined)
|
||||
detectedStacks.push('go');
|
||||
else if (
|
||||
read(root, 'uv.lock', true) !== undefined ||
|
||||
read(root, 'requirements.txt', true) !== undefined ||
|
||||
@@ -1231,10 +1234,16 @@ export function inspectPreparation(snapshotPath: string, stack?: CsoStack): Prep
|
||||
`Java (${jvmBuild ?? 'Maven or Gradle'}) is not a supported runtime stack yet; supported runtime stacks are Node, Bun, Python, and Rails.`,
|
||||
jvmBuild,
|
||||
);
|
||||
if (detected === 'go')
|
||||
fail(
|
||||
'UNSUPPORTED_STACK',
|
||||
'Go (go.mod) is not a supported runtime stack yet; supported runtime stacks are Node, Bun, Python, and Rails.',
|
||||
'go.mod',
|
||||
);
|
||||
if (!['node', 'bun', 'python', 'rails'].includes(detected))
|
||||
fail('UNSUPPORTED_STACK', 'Supported runtime stacks are Node, Bun, Python, and Rails.');
|
||||
({ node: inspectNode, bun: inspectBun, python: inspectPython, rails: inspectRails })[
|
||||
detected as Exclude<CsoStack, 'java'>
|
||||
detected as Exclude<CsoStack, 'java' | 'go'>
|
||||
](root, plan);
|
||||
} catch (error) {
|
||||
plan.status = 'prerequisites';
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gstack",
|
||||
"version": "1.91.199",
|
||||
"version": "1.91.200",
|
||||
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
|
||||
@@ -170,6 +170,32 @@ describe('CSO inert Python preparation', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('CSO preparation names a Go module as Go (#3263)', () => {
|
||||
const goFiles = {
|
||||
'go.mod': 'module example.com/app\n\ngo 1.23\n\nrequire github.com/google/uuid v1.6.0\n',
|
||||
'go.sum': 'github.com/google/uuid v1.6.0 h1:abc=\n',
|
||||
'main.go': 'package main\n\nfunc main() {}\n',
|
||||
};
|
||||
const GO_UNSUPPORTED = { code: 'UNSUPPORTED_STACK', message: 'Go (go.mod) is not a supported runtime stack yet; supported runtime stacks are Node, Bun, Python, and Rails.', path: 'go.mod' };
|
||||
test('a go.mod repository is Go, unsupported, and never asks for requirements.txt', () => {
|
||||
const plan = inspectPreparation(fixture(goFiles));
|
||||
expect([plan.stack, plan.runtimeProfile, plan.status]).toEqual(['go', 'go', 'prerequisites']);
|
||||
expect(plan.prerequisites).toEqual([GO_UNSUPPORTED]);
|
||||
expect(JSON.stringify(plan)).not.toContain('requirements.txt');
|
||||
});
|
||||
test('Python helper metadata beside go.mod stays Go', () => {
|
||||
const plan = inspectPreparation(fixture({ ...goFiles, 'requirements.txt': `mkdocs==1.6.1 --hash=sha256:${hash}\n` }));
|
||||
expect(plan.stack).toBe('go');
|
||||
expect(plan.prerequisites).toEqual([GO_UNSUPPORTED]);
|
||||
});
|
||||
test('controls: go.mod beside a Node lockfile stays Node; Python without go.mod stays Python', () => {
|
||||
const node = inspectPreparation(fixture({ ...goFiles, ...nodeFiles() }));
|
||||
expect([node.stack, node.status]).toEqual(['node', 'ready']);
|
||||
expect(inspectPreparation(fixture({ 'requirements.txt': `Flask==3.1.0 --hash=sha256:${hash}\n` })).stack).toBe('python');
|
||||
expect(inspectPreparation(fixture({ 'go.sum': '', 'main.go': '' })).stack).toBe('python');
|
||||
});
|
||||
});
|
||||
|
||||
describe('CSO inert Rails preparation', () => {
|
||||
test('does not silently choose Node in a multi-stack repository',()=>{const plan=inspectPreparation(fixture({...nodeFiles(),'Gemfile.lock':gemLock,'Gemfile':''}));expect(plan.status).toBe('prerequisites');expect(plan.prerequisites[0].code).toBe('MULTIPLE_STACKS');expect(inspectPreparation(fixture({...nodeFiles(),'Gemfile.lock':gemLock,'Gemfile':''}),'rails').stack).toBe('rails');});
|
||||
test('fetches exact gems without evaluating Gemfiles or building native extensions', () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { CsoStack } from '../../lib/cso/preparation';
|
||||
|
||||
type RuntimeStack = Exclude<CsoStack, 'java'>;
|
||||
type RuntimeStack = Exclude<CsoStack, 'java' | 'go'>;
|
||||
import { canonical, sha256 } from '../../lib/cso/contracts';
|
||||
import { ISOLATION_POLICY_HASH } from '../../lib/cso/docker';
|
||||
import {
|
||||
|
||||
Reference in new issue
Block a user