entropy-machines 0.1.1 → 0.1.3
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/README.md +2 -2
- package/bin/entropy-machines-init +27 -15
- package/bin/init +15 -8
- package/bin/serve +25 -12
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# entropy-machines
|
|
2
2
|
|
|
3
|
-
Escape the terminal. Enter your
|
|
3
|
+
Escape the terminal. Enter your factory floor.
|
|
4
4
|
|
|
5
5
|
You create PRDs, design with agents, and once your decisions are complete,
|
|
6
6
|
issues are generated from those PRDs. Worker agents execute each issue in
|
|
@@ -24,7 +24,7 @@ the decisions only you can make. Everything downstream follows from your answers
|
|
|
24
24
|
## Get started
|
|
25
25
|
|
|
26
26
|
```sh
|
|
27
|
-
npx entropy start
|
|
27
|
+
npx entropy-machines start
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
This vendors the harness into your git repo (if it hasn't been already) and
|
|
@@ -47,6 +47,15 @@ const NPM_ENTRY = path.basename(__filename);
|
|
|
47
47
|
|
|
48
48
|
const DEFAULT_DIR = 'entropy-machines';
|
|
49
49
|
|
|
50
|
+
// ANSI color, gated on tty + NO_COLOR (https://no-color.org/).
|
|
51
|
+
const USE_COLOR = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
52
|
+
const BOLD = USE_COLOR ? '\x1b[1m' : '';
|
|
53
|
+
const DIM = USE_COLOR ? '\x1b[2m' : '';
|
|
54
|
+
const GREEN = USE_COLOR ? '\x1b[32m' : '';
|
|
55
|
+
const YELLOW = USE_COLOR ? '\x1b[33m' : '';
|
|
56
|
+
const CYAN = USE_COLOR ? '\x1b[36m' : '';
|
|
57
|
+
const RESET = USE_COLOR ? '\x1b[0m' : '';
|
|
58
|
+
|
|
50
59
|
function die(lines) {
|
|
51
60
|
for (const line of [].concat(lines)) console.error(line);
|
|
52
61
|
process.exit(2);
|
|
@@ -55,8 +64,8 @@ function die(lines) {
|
|
|
55
64
|
function usage() {
|
|
56
65
|
console.log(`entropy-machines ${PKG.version}
|
|
57
66
|
|
|
58
|
-
npx entropy start # init (if needed) + open the PRD
|
|
59
|
-
npx entropy init [--dir <path>] # vendor the harness only
|
|
67
|
+
npx entropy-machines start # init (if needed) + open the PRD
|
|
68
|
+
npx entropy-machines init [--dir <path>] # vendor the harness only
|
|
60
69
|
|
|
61
70
|
start: vendors the harness if config.json is absent, then launches
|
|
62
71
|
bin/serve — which opens your first PRD in a browser.
|
|
@@ -196,31 +205,31 @@ function init(argv) {
|
|
|
196
205
|
}
|
|
197
206
|
|
|
198
207
|
const shown = path.relative(root, dest) || '.';
|
|
199
|
-
console.log(
|
|
200
|
-
for (const d of HARNESS_DIRS) console.log(` ${path.join(shown, d)}
|
|
201
|
-
console.log(` ${path.join(shown, 'LICENSE')}${licenseNote}`);
|
|
208
|
+
console.log(`${GREEN}entropy-machines ${PKG.version}: vendored into ${dest}${RESET}`);
|
|
209
|
+
for (const d of HARNESS_DIRS) console.log(` ${DIM}${path.join(shown, d)}/${RESET}`);
|
|
210
|
+
console.log(` ${DIM}${path.join(shown, 'LICENSE')}${licenseNote}${RESET}`);
|
|
202
211
|
console.log('');
|
|
203
212
|
|
|
204
213
|
// ---- Hand over to the harness. Everything past here is shell + Python. ----
|
|
205
214
|
|
|
206
215
|
const vendoredInit = path.join(dest, 'bin', 'init');
|
|
207
|
-
console.log(`entropy-machines: running ${path.join(shown, 'bin', 'init')}`);
|
|
216
|
+
console.log(`entropy-machines: running ${DIM}${path.join(shown, 'bin', 'init')}${RESET}`);
|
|
208
217
|
const r = spawnSync(vendoredInit, [], { cwd: root, stdio: 'inherit' });
|
|
209
218
|
if (r.error) {
|
|
210
|
-
console.error(
|
|
211
|
-
console.error(
|
|
219
|
+
console.error(`${YELLOW}entropy-machines: could not run ${vendoredInit}: ${r.error.message}${RESET}`);
|
|
220
|
+
console.error(` The files ARE vendored. Run it yourself from the repo root.`);
|
|
212
221
|
process.exit(2);
|
|
213
222
|
}
|
|
214
223
|
if (r.status !== 0) {
|
|
215
224
|
console.error('');
|
|
216
|
-
console.error(
|
|
225
|
+
console.error(`${YELLOW}entropy-machines: the files are vendored, but bin/init did not${RESET}`);
|
|
217
226
|
console.error(' finish. Fix what it named above and re-run it from the repo');
|
|
218
|
-
console.error(` root: ${path.join(shown, 'bin', 'init')}`);
|
|
227
|
+
console.error(` root: ${CYAN}${path.join(shown, 'bin', 'init')}${RESET}`);
|
|
219
228
|
process.exit(r.status === null ? 2 : r.status);
|
|
220
229
|
}
|
|
221
230
|
|
|
222
231
|
console.log('');
|
|
223
|
-
console.log(
|
|
232
|
+
console.log(`${BOLD}entropy-machines: done. Next —${RESET}`);
|
|
224
233
|
// Named paths only, never a guessed docs directory — that one is config
|
|
225
234
|
// (docs.dir), and CONFIG.md rule 1 makes a hardcoded path in bin/ a bug.
|
|
226
235
|
// NEVER `git add .` for the root layout. This command is reached over npm,
|
|
@@ -231,9 +240,12 @@ function init(argv) {
|
|
|
231
240
|
shown === '.'
|
|
232
241
|
? `${HARNESS_DIRS.join(' ')} LICENSE .gitignore`
|
|
233
242
|
: `${shown} .gitignore`;
|
|
234
|
-
|
|
235
|
-
console.log(`
|
|
236
|
-
|
|
243
|
+
// Step 1: agent context (most important — the agent needs this first)
|
|
244
|
+
console.log(` ${BOLD}1. point your coding agent at ${CYAN}${path.join(shown, 'docs', 'AGENT-QUICKSTART.md')}${RESET}`);
|
|
245
|
+
// Step 2: run serve to get the PRD
|
|
246
|
+
console.log(` 2. ${CYAN}${path.join(shown, 'bin', 'serve')}${RESET} — answer the PRD it opens (creates issues)`);
|
|
247
|
+
// Step 3: commit (least urgent)
|
|
248
|
+
console.log(` ${DIM}3. commit what init wrote: git add ${addPaths}${RESET}`);
|
|
237
249
|
}
|
|
238
250
|
|
|
239
251
|
function findHarness(root) {
|
|
@@ -262,7 +274,7 @@ function start(argv) {
|
|
|
262
274
|
if (!fs.existsSync(serve)) {
|
|
263
275
|
die([`entropy-machines: ${path.join(loc.shown, 'bin', 'serve')} not found.`]);
|
|
264
276
|
}
|
|
265
|
-
console.log(`\
|
|
277
|
+
console.log(`\n${BOLD}entropy-machines: starting serve from ${loc.shown}/${RESET}\n`);
|
|
266
278
|
const r = spawnSync('sh', [serve], { cwd: loc.dir, stdio: 'inherit' });
|
|
267
279
|
process.exit(r.status ?? 1);
|
|
268
280
|
}
|
package/bin/init
CHANGED
|
@@ -18,6 +18,13 @@
|
|
|
18
18
|
# --force overwrite an existing config.json.
|
|
19
19
|
set -e
|
|
20
20
|
|
|
21
|
+
# ---- ANSI color, gated on tty + NO_COLOR (https://no-color.org/) ----
|
|
22
|
+
if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then
|
|
23
|
+
BOLD='\033[1m' DIM='\033[2m' GREEN='\033[32m' YELLOW='\033[33m' CYAN='\033[36m' RESET='\033[0m'
|
|
24
|
+
else
|
|
25
|
+
BOLD='' DIM='' GREEN='' YELLOW='' CYAN='' RESET=''
|
|
26
|
+
fi
|
|
27
|
+
|
|
21
28
|
usage() {
|
|
22
29
|
cat >&2 <<'EOF'
|
|
23
30
|
usage: bin/init [--force]
|
|
@@ -195,18 +202,18 @@ fi
|
|
|
195
202
|
# in fact everything was — and a plain re-run then died on "config.json
|
|
196
203
|
# already exists" with no repair path named.
|
|
197
204
|
if ! (cd "$project" && "$ENTROPY_MACHINES_HOME/bin/tracker" ready >/dev/null 2>&1); then
|
|
198
|
-
|
|
205
|
+
printf "${YELLOW}init: WARNING — $target was WRITTEN, but bin/tracker could not read the${RESET}\n" >&2
|
|
199
206
|
echo " tracker back afterward. This is not a refusal: everything above" >&2
|
|
200
207
|
echo " really was written, and the project is half-initialised." >&2
|
|
201
|
-
|
|
208
|
+
printf " Check ${DIM}$project/.entropy-machines/${RESET} and ${DIM}$target${RESET} by hand.\n" >&2
|
|
202
209
|
echo " To re-run once you have fixed it (a plain re-run will refuse," >&2
|
|
203
210
|
echo " because config.json now exists):" >&2
|
|
204
|
-
|
|
211
|
+
printf " ${CYAN}$ENTROPY_MACHINES_HOME/bin/init --force${RESET}\n" >&2
|
|
205
212
|
exit 2
|
|
206
213
|
fi
|
|
207
214
|
|
|
208
|
-
|
|
209
|
-
|
|
215
|
+
printf "${GREEN}init: wrote $target${RESET}\n"
|
|
216
|
+
printf "${GREEN}$prd_note${RESET}\n"
|
|
210
217
|
if [ -n "$prd_written" ]; then
|
|
211
218
|
echo " questions in it are the ones only you can answer."
|
|
212
219
|
fi
|
|
@@ -225,8 +232,8 @@ esac
|
|
|
225
232
|
# the first document the harness hands them would otherwise hit a 404 — which
|
|
226
233
|
# is exactly the bug that made this necessary.
|
|
227
234
|
"$ENTROPY_MACHINES_HOME/bin/tracker" render >/dev/null 2>&1 || \
|
|
228
|
-
|
|
235
|
+
printf "${YELLOW}init: warning — could not render TRACKER.html; run \`${CYAN}$cmd_prefix/tracker render${YELLOW}\`${RESET}\n" >&2
|
|
229
236
|
|
|
230
|
-
|
|
231
|
-
|
|
237
|
+
printf "${GREEN}init: tracker is live and empty${RESET} — \`${CYAN}$cmd_prefix/tracker ready${RESET}\` answers.\n"
|
|
238
|
+
printf "${BOLD}init: next — run \`${CYAN}$cmd_prefix/serve${RESET}${BOLD}\` and answer the PRD it opens.${RESET}\n"
|
|
232
239
|
echo " Filing the issues it produces is step one."
|
package/bin/serve
CHANGED
|
@@ -690,18 +690,31 @@ class Handler(BaseHTTPRequestHandler):
|
|
|
690
690
|
|
|
691
691
|
|
|
692
692
|
def main():
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
693
|
+
# TRY THE REQUESTED PORT, THEN SCAN UPWARD. A user running `npx
|
|
694
|
+
# entropy-machines start` for the first time should not be stopped by a
|
|
695
|
+
# stale process on 8787 — the server picks the next open port and says
|
|
696
|
+
# which one it got. Cap at 20 attempts so a misconfigured machine gets a
|
|
697
|
+
# clear error, not an infinite loop.
|
|
698
|
+
MAX_ATTEMPTS = 20
|
|
699
|
+
port = PORT
|
|
700
|
+
server = None
|
|
701
|
+
for attempt in range(MAX_ATTEMPTS):
|
|
702
|
+
try:
|
|
703
|
+
server = ThreadingHTTPServer(("127.0.0.1", port), Handler)
|
|
704
|
+
break
|
|
705
|
+
except OSError as exc:
|
|
706
|
+
if exc.errno == 48 or "Address already in use" in str(exc):
|
|
707
|
+
if attempt == 0 and port == PORT:
|
|
708
|
+
print("serve: port %d busy, scanning for an open port…" % port,
|
|
709
|
+
file=sys.stderr, flush=True)
|
|
710
|
+
port += 1
|
|
711
|
+
continue
|
|
712
|
+
print("serve: REFUSED — could not bind 127.0.0.1:%d (%s)." % (port, exc),
|
|
713
|
+
file=sys.stderr)
|
|
703
714
|
sys.exit(1)
|
|
704
|
-
|
|
715
|
+
if server is None:
|
|
716
|
+
print("serve: REFUSED — ports %d–%d all busy." % (PORT, PORT + MAX_ATTEMPTS - 1),
|
|
717
|
+
file=sys.stderr)
|
|
705
718
|
sys.exit(1)
|
|
706
719
|
# flush=True IS THE POINT OF THESE TWO LINES. Python block-buffers stdout
|
|
707
720
|
# when it is not a tty — which is exactly the case a bootstrapping agent
|
|
@@ -710,7 +723,7 @@ def main():
|
|
|
710
723
|
# never drained, because the very next statement blocks in serve_forever()
|
|
711
724
|
# forever; the log stays 0 bytes while the server runs and 0 bytes after
|
|
712
725
|
# it is killed. The URL is the one thing this command exists to produce.
|
|
713
|
-
print("serving %s on http://localhost:%d" % (ENTROPY_MACHINES_ROOT,
|
|
726
|
+
print("serving %s on http://localhost:%d" % (ENTROPY_MACHINES_ROOT, port), flush=True)
|
|
714
727
|
print(" docs: %s (%s)" % (DOCS_PATH, DOCS_DIR), flush=True)
|
|
715
728
|
print(" theme: %s (%s)" % (THEME_NAME, THEME_FILE), flush=True)
|
|
716
729
|
try:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "entropy-machines",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Vendors the entropy-machines agent-orchestration harness into your git repository as plain tracked files. A delivery mechanism, not a runtime — the harness is POSIX shell and Python 3 and needs no Node once the files have landed.",
|
|
5
5
|
"license": "Elastic-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
"url": "https://github.com/modern-sapien/entropy-machines/issues"
|
|
13
13
|
},
|
|
14
14
|
"bin": {
|
|
15
|
-
"entropy": "bin/entropy-machines-init",
|
|
16
15
|
"entropy-machines": "bin/entropy-machines-init"
|
|
17
16
|
},
|
|
18
17
|
"files": [
|