agent-bios 0.10.0 → 0.12.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/DEPENDENCIES.md +3 -3
- package/README.md +4 -4
- package/claude/guides/cli-multi-model-workflow.md +50 -4
- package/claude/guides/coding-staged-workflow.md +1 -1
- package/claude/guides/session-distill-workflow.md +3 -3
- package/claude/hooks/tooling-gotchas-hook.py +37 -2
- package/claude/skills/repo-charter/SKILL.md +149 -0
- package/codex/guides/cli-multi-model-workflow.md +50 -4
- package/codex/guides/coding-staged-workflow.md +1 -1
- package/codex/guides/session-distill-workflow.md +3 -3
- package/compose/assemble.py +184 -21
- package/compose/canary.sh +13 -0
- package/compose/check-domains.py +144 -20
- package/compose/domains.json +3 -0
- package/compose/prune-backups.py +57 -7
- package/install.sh +442 -30
- package/launch/agent-launch.py +4567 -659
- package/launch/agent-launch.toml +65 -110
- package/launch/agent-launch.zsh +7 -2
- package/launch/i18n/en.toml +186 -0
- package/launch/i18n/ja.toml +182 -0
- package/launch/i18n/ko.toml +182 -0
- package/learn/check-learning.py +19 -1
- package/learn/collect-learning.py +57 -2
- package/learn/migrate-learnings.py +140 -16
- package/learn/redact.py +14 -5
- package/package.json +4 -2
- package/provenance.json +1 -1
- package/session-cost.py +402 -33
- package/wrappers/claude-run.sh +49 -4
- package/wrappers/codex-run.sh +1 -1
package/compose/prune-backups.py
CHANGED
|
@@ -94,18 +94,29 @@ def prune(state_dir, homes, now=None, dry=False):
|
|
|
94
94
|
now = time.time() if now is None else now
|
|
95
95
|
removed = []
|
|
96
96
|
|
|
97
|
+
# Recorded AFTER the removal is confirmed gone. Both deleters swallow their errors on
|
|
98
|
+
# purpose — a backup that will not delete must not fail an install — but appending
|
|
99
|
+
# first made the returned list a record of what was ATTEMPTED, and the caller prints it
|
|
100
|
+
# as what was removed. A copy still on disk being reported as pruned is the reading
|
|
101
|
+
# that sends someone looking for space that was never freed.
|
|
102
|
+
def take(path, remove):
|
|
103
|
+
if dry:
|
|
104
|
+
removed.append(path)
|
|
105
|
+
return
|
|
106
|
+
remove(path)
|
|
107
|
+
if path.exists():
|
|
108
|
+
print(f" warning: could not remove {path}", file=sys.stderr)
|
|
109
|
+
return
|
|
110
|
+
removed.append(path)
|
|
111
|
+
|
|
97
112
|
backups = state_dir / "backups"
|
|
98
113
|
if backups.is_dir():
|
|
99
114
|
for path in to_delete(_entries([d for d in backups.iterdir() if d.is_dir()]), now):
|
|
100
|
-
|
|
101
|
-
if not dry:
|
|
102
|
-
shutil.rmtree(path, ignore_errors=True)
|
|
115
|
+
take(path, lambda p: shutil.rmtree(p, ignore_errors=True))
|
|
103
116
|
|
|
104
117
|
for home in homes:
|
|
105
118
|
for path in to_delete(_entries(owned_siblings(home)), now):
|
|
106
|
-
|
|
107
|
-
if not dry:
|
|
108
|
-
path.unlink(missing_ok=True)
|
|
119
|
+
take(path, lambda p: p.unlink(missing_ok=True))
|
|
109
120
|
return removed
|
|
110
121
|
|
|
111
122
|
|
|
@@ -163,7 +174,46 @@ def self_test():
|
|
|
163
174
|
if not missed and not grabbed:
|
|
164
175
|
print(f" ok ownership: claims {len(ours)} shapes we write, "
|
|
165
176
|
f"refuses {len(theirs)} we do not")
|
|
166
|
-
|
|
177
|
+
# The reported list is what the caller prints as removed, so it has to be what is GONE.
|
|
178
|
+
# Both deleters swallow their errors by design — a stuck copy must not fail an install —
|
|
179
|
+
# and appending before the call made the list a record of attempts instead. Driven on a
|
|
180
|
+
# real directory, because the defect lives in the deletion and not in the pure retention
|
|
181
|
+
# rule above; the deletable run beside it is what keeps this from passing on a pruner
|
|
182
|
+
# that reports nothing at all.
|
|
183
|
+
import os as os_, tempfile as tempfile_
|
|
184
|
+
|
|
185
|
+
def reported_vs_gone(block_one):
|
|
186
|
+
root = pathlib.Path(tempfile_.mkdtemp())
|
|
187
|
+
state = root / "state"
|
|
188
|
+
(state / "backups").mkdir(parents=True)
|
|
189
|
+
made = []
|
|
190
|
+
for i in range(KEEP_RECENT + 2):
|
|
191
|
+
aged = state / "backups" / f"2020{i:04d}-000000"
|
|
192
|
+
aged.mkdir()
|
|
193
|
+
(aged / "f.txt").write_text("x")
|
|
194
|
+
stamp = now - (MAX_AGE_DAYS + 10 + i) * day
|
|
195
|
+
os_.utime(aged, (stamp, stamp))
|
|
196
|
+
made.append(aged)
|
|
197
|
+
stuck = sorted(made, key=lambda q: q.stat().st_mtime)[0]
|
|
198
|
+
if block_one:
|
|
199
|
+
stuck.chmod(0o500)
|
|
200
|
+
count = len(prune(state, [], now=now))
|
|
201
|
+
gone = len([q for q in made if not q.exists()])
|
|
202
|
+
if block_one:
|
|
203
|
+
stuck.chmod(0o700)
|
|
204
|
+
shutil.rmtree(root, ignore_errors=True)
|
|
205
|
+
return count, gone
|
|
206
|
+
|
|
207
|
+
for label, block_one in (("every aged backup deletable", False),
|
|
208
|
+
("one of them undeletable", True)):
|
|
209
|
+
count, gone = reported_vs_gone(block_one)
|
|
210
|
+
if count != gone or (not block_one and gone == 0):
|
|
211
|
+
print(f" FAIL {label}: reported {count} removed, {gone} actually gone")
|
|
212
|
+
bad += 1
|
|
213
|
+
else:
|
|
214
|
+
print(f" ok {label}: reported {count} == gone {gone}")
|
|
215
|
+
|
|
216
|
+
print(f"prune-backups self-test: {'OK' if not bad else 'FAIL'} ({len(cases) + 4} checks)")
|
|
167
217
|
return 1 if bad else 0
|
|
168
218
|
|
|
169
219
|
|