atris 3.57.4 → 3.58.5
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 +12 -1
- package/atris/skills/clawhub/member-runtime/SKILL.md +9 -9
- package/atris/skills/create-member/SKILL.md +16 -13
- package/atris/skills/design/SKILL.md +27 -4
- package/atris/skills/engines/SKILL.md +55 -12
- package/atris/skills/x-search/SKILL.md +8 -6
- package/atris/skills/youtube/SKILL.md +37 -8
- package/atris/team/brainstormer/MEMBER.md +2 -2
- package/atris/team/executor/MEMBER.md +3 -3
- package/atris/team/launcher/MEMBER.md +4 -4
- package/atris/team/navigator/MEMBER.md +3 -3
- package/atris/team/researcher/MEMBER.md +2 -2
- package/atris/team/validator/MEMBER.md +1 -1
- package/atris.md +14 -0
- package/ax +153 -23
- package/bin/atris.js +78 -30
- package/commands/aeo.js +4 -4
- package/commands/agents.js +1 -1
- package/commands/align.js +12 -12
- package/commands/analytics.js +3 -3
- package/commands/app.js +5 -5
- package/commands/ask.js +175 -0
- package/commands/auth.js +7 -7
- package/commands/autoland.js +29 -5
- package/commands/autopilot-front.js +6 -6
- package/commands/autopilot.js +90 -90
- package/commands/avail.js +5 -5
- package/commands/bench.js +63 -1
- package/commands/browse.js +2 -2
- package/commands/business.js +12 -12
- package/commands/card.js +2 -2
- package/commands/clean.js +13 -13
- package/commands/close.js +3 -3
- package/commands/compile.js +13 -13
- package/commands/computer.js +94 -27
- package/commands/console.js +5 -5
- package/commands/decide.js +1 -1
- package/commands/deck.js +9 -9
- package/commands/drive.js +4 -4
- package/commands/engine.js +173 -19
- package/commands/errors.js +3 -3
- package/commands/experiments.js +18 -1
- package/commands/feed.js +2 -2
- package/commands/feedback.js +4 -4
- package/commands/fleet.js +12 -12
- package/commands/game.js +1 -1
- package/commands/guide.js +49 -0
- package/commands/improve.js +19 -17
- package/commands/init.js +67 -19
- package/commands/interview.js +7 -7
- package/commands/land.js +40 -15
- package/commands/learn.js +12 -12
- package/commands/lesson.js +2 -2
- package/commands/log.js +1 -1
- package/commands/loops.js +4 -4
- package/commands/member.js +75 -50
- package/commands/mission.js +90 -82
- package/commands/one-lap.js +1 -1
- package/commands/pack.js +74 -8
- package/commands/plugin.js +6 -6
- package/commands/probe.js +9 -9
- package/commands/pull.js +35 -35
- package/commands/pulse.js +1 -1
- package/commands/push.js +21 -21
- package/commands/rainmaker.js +1 -1
- package/commands/recap.js +7 -7
- package/commands/reel.js +2 -2
- package/commands/release.js +3 -3
- package/commands/report.js +1 -1
- package/commands/review.js +5 -5
- package/commands/revisions.js +1 -1
- package/commands/run.js +1 -1
- package/commands/scout.js +3 -3
- package/commands/security-review.js +7 -7
- package/commands/serve.js +9 -9
- package/commands/setup.js +1 -1
- package/commands/sign.js +4 -4
- package/commands/signup.js +4 -4
- package/commands/site.js +8 -3
- package/commands/skill.js +6 -6
- package/commands/slop.js +18 -18
- package/commands/social.js +3 -3
- package/commands/soul.js +14 -14
- package/commands/spaceship.js +1 -1
- package/commands/status.js +2 -2
- package/commands/strings.js +13 -13
- package/commands/study.js +4 -4
- package/commands/sync.js +8 -8
- package/commands/task.js +50 -25
- package/commands/teach.js +2 -2
- package/commands/team.js +1 -1
- package/commands/theme.js +2 -2
- package/commands/tree.js +34 -0
- package/commands/truth.js +7 -7
- package/commands/verify.js +12 -12
- package/commands/visualize.js +2 -2
- package/commands/workflow.js +97 -40
- package/commands/worktree.js +1 -1
- package/commands/write.js +9 -9
- package/commands/x-search.js +89 -17
- package/commands/xp.js +6 -3
- package/commands/youtube.js +601 -48
- package/lib/accept-verify-gate.js +3 -3
- package/lib/activity-stream.js +1 -1
- package/lib/auto-accept-certified.js +28 -12
- package/lib/autoland.js +6 -6
- package/lib/bench/engines.js +59 -8
- package/lib/bench/report.js +1 -1
- package/lib/bench/runner.js +204 -5
- package/lib/bench/tree-render.js +76 -0
- package/lib/card.js +1 -1
- package/lib/chat-log-scan.js +1 -1
- package/lib/claude-boot-block.js +2 -0
- package/lib/deck-compose.js +1 -1
- package/lib/deck-history.js +2 -2
- package/lib/deck-layout.js +1 -1
- package/lib/deck-review.js +5 -5
- package/lib/deck-schema.js +1 -1
- package/lib/default-verifier.js +1 -1
- package/lib/developer-api.js +3 -0
- package/lib/engine-ask.js +45 -7
- package/lib/engine-registry.js +15 -2
- package/lib/file-ops.js +1 -1
- package/lib/fleet.js +71 -35
- package/lib/html-render.js +1 -1
- package/lib/intents.js +172 -0
- package/lib/journal.js +1 -1
- package/lib/known-commands.js +2 -2
- package/lib/land-green.js +364 -0
- package/lib/lesson-contradiction.js +2 -2
- package/lib/lesson-preflight.js +1 -1
- package/lib/manifest.js +5 -5
- package/lib/member-alive.js +9 -5
- package/lib/memory-view.js +3 -3
- package/lib/mission-protected-lane.js +1 -1
- package/lib/mission-root.js +2 -2
- package/lib/orb-context.js +10 -10
- package/lib/pack-capabilities.js +861 -3
- package/lib/permission-grants.js +2 -2
- package/lib/policy-lessons.js +6 -6
- package/lib/pulse.js +8 -8
- package/lib/receipt-evidence.js +1 -1
- package/lib/reel.js +1 -1
- package/lib/review-integrity.js +1 -1
- package/lib/runner-command.js +35 -5
- package/lib/scorecard.js +4 -4
- package/lib/security-scan.js +5 -5
- package/lib/self-drive.js +1 -1
- package/lib/site-publish.js +372 -0
- package/lib/site.js +1 -1
- package/lib/slides-deck.js +2 -2
- package/lib/state-detection.js +2 -2
- package/lib/sync-telemetry.js +2 -2
- package/lib/task-db.js +17 -10
- package/lib/task-explanation.js +1 -1
- package/lib/task-proof.js +2 -2
- package/lib/task-receipt.js +3 -3
- package/lib/theme.js +12 -12
- package/lib/todo-fallback.js +3 -3
- package/lib/todo-sections.js +1 -1
- package/lib/tree-hash.js +79 -0
- package/lib/usage.js +1 -1
- package/lib/wish-delegate.js +1 -1
- package/lib/workspace-safety.js +4 -4
- package/lib/workspace-scaffold.js +3 -3
- package/package.json +1 -1
- package/scripts/det/concierge-bakeoff.sh +26 -0
- package/scripts/det/ytquote-repair.js +0 -1
- package/scripts/det/ytrail-race.js +0 -5
- package/scripts/member-operate.mjs +52 -14
- package/scripts/outbound-artifact-gate.js +0 -3
- package/utils/auth.js +0 -3
- package/utils/config.js +0 -1
- package/scripts/det/checklist-score.js +0 -191
package/commands/push.js
CHANGED
|
@@ -491,7 +491,7 @@ async function pushAtris() {
|
|
|
491
491
|
// Push the whole business workspace by default. Brain-only sync must be
|
|
492
492
|
// explicit with --only atris/ so root workspace files cannot be missed.
|
|
493
493
|
|
|
494
|
-
// Resolve business
|
|
494
|
+
// Resolve business, always refresh from API
|
|
495
495
|
let businessId, workspaceId, businessName, resolvedSlug;
|
|
496
496
|
const businesses = loadBusinesses();
|
|
497
497
|
const listResult = await apiRequestJson('/business/', { method: 'GET', token: creds.token });
|
|
@@ -516,7 +516,7 @@ async function pushAtris() {
|
|
|
516
516
|
|
|
517
517
|
if (!workspaceId) { console.error(`Business "${slug}" has no workspace.`); process.exit(1); }
|
|
518
518
|
|
|
519
|
-
// Telemetry helper
|
|
519
|
+
// Telemetry helper, emits one event with the elapsed wall-clock time.
|
|
520
520
|
// Awaited (not fire-and-forget) because process.exit kills in-flight requests.
|
|
521
521
|
const emit = (outcome, extras = {}) =>
|
|
522
522
|
emitSyncEvent(creds.token, businessId, workspaceId, 'push', outcome, elapsedMs(), extras);
|
|
@@ -590,12 +590,12 @@ async function pushAtris() {
|
|
|
590
590
|
console.log(`Pushing to ${businessName}...`);
|
|
591
591
|
|
|
592
592
|
// ───────────────────────────────────────────────────────────────────
|
|
593
|
-
// FRESHNESS CHECK
|
|
593
|
+
// FRESHNESS CHECK, pull-before-push enforcement.
|
|
594
594
|
// ───────────────────────────────────────────────────────────────────
|
|
595
595
|
// Compare cloud's current state to our local manifest. If cloud has any
|
|
596
596
|
// file the manifest doesn't know about, OR a file with a different hash
|
|
597
597
|
// than what we last pulled, the user is out of date and MUST pull first.
|
|
598
|
-
// This prevents stale local state from clobbering fresh cloud changes
|
|
598
|
+
// This prevents stale local state from clobbering fresh cloud changes,
|
|
599
599
|
// the "lagging version push" footgun. Use --force to bypass (e.g., for
|
|
600
600
|
// genuine local-canonical pushes like align --hard).
|
|
601
601
|
if (!force) {
|
|
@@ -624,7 +624,7 @@ async function pushAtris() {
|
|
|
624
624
|
// files on the next push, undoing the deletion.
|
|
625
625
|
//
|
|
626
626
|
// CAVEAT: the warm runner's snapshot endpoint deliberately hides certain
|
|
627
|
-
// basenames (CLAUDE.md, .* dotfiles, node_modules, __pycache__, .git)
|
|
627
|
+
// basenames (CLAUDE.md, .* dotfiles, node_modules, __pycache__, .git),
|
|
628
628
|
// see ecs_warm_runner.py _snapshot_dir. They CAN exist on cloud but
|
|
629
629
|
// never appear in cloudHashes. Skip them in the missing-side check or
|
|
630
630
|
// every CLAUDE.md push will be flagged as drift forever.
|
|
@@ -646,7 +646,7 @@ async function pushAtris() {
|
|
|
646
646
|
}
|
|
647
647
|
console.log('fresh');
|
|
648
648
|
} else {
|
|
649
|
-
// Snapshot fetch failed
|
|
649
|
+
// Snapshot fetch failed, fail closed. The whole point of the freshness
|
|
650
650
|
// check is to prevent accidental stale pushes; if we can't verify cloud
|
|
651
651
|
// state, we don't push. Use --force to bypass when you know what you're
|
|
652
652
|
// doing (e.g., the workspace is genuinely unhealthy and you have a clean
|
|
@@ -661,7 +661,7 @@ async function pushAtris() {
|
|
|
661
661
|
}
|
|
662
662
|
}
|
|
663
663
|
|
|
664
|
-
// Compare local hashes to manifest
|
|
664
|
+
// Compare local hashes to manifest, NO server call needed
|
|
665
665
|
// Files where local hash differs from manifest = changed locally
|
|
666
666
|
if (parsed.changed && Array.isArray(onlyPrefixes) && onlyPrefixes.length === 0 && (!parsed.pathArgs || parsed.pathArgs.length === 0) && !parsed.onlyRaw) {
|
|
667
667
|
console.log('\n Already up to date.\n');
|
|
@@ -699,7 +699,7 @@ async function pushAtris() {
|
|
|
699
699
|
process.exit(1);
|
|
700
700
|
}
|
|
701
701
|
|
|
702
|
-
// Dry run
|
|
702
|
+
// Dry run, show what would be pushed without pushing
|
|
703
703
|
if (dryRun) {
|
|
704
704
|
console.log('');
|
|
705
705
|
for (const f of filesToPush) {
|
|
@@ -765,7 +765,7 @@ async function pushAtris() {
|
|
|
765
765
|
// The /sync endpoint can silently drop files (role-based filters on the
|
|
766
766
|
// business workspace route, path-rejection inside the warm runner, etc.)
|
|
767
767
|
// and still return HTTP 200. If we don't cross-check per-file results,
|
|
768
|
-
// the CLI prints "Pushed" for files that never actually landed
|
|
768
|
+
// the CLI prints "Pushed" for files that never actually landed, and
|
|
769
769
|
// the manifest records a hash that makes the next push skip them too,
|
|
770
770
|
// losing them permanently. `failedToLand` collects those casualties so
|
|
771
771
|
// we can warn the user AND keep them out of the manifest update.
|
|
@@ -818,7 +818,7 @@ async function pushAtris() {
|
|
|
818
818
|
}
|
|
819
819
|
}
|
|
820
820
|
} else {
|
|
821
|
-
// No results array in response
|
|
821
|
+
// No results array in response, old server. Best-effort: assume
|
|
822
822
|
// everything sent landed. This preserves existing behavior when
|
|
823
823
|
// talking to a server that doesn't return per-file status.
|
|
824
824
|
for (const f of sentFiles) {
|
|
@@ -835,7 +835,7 @@ async function pushAtris() {
|
|
|
835
835
|
};
|
|
836
836
|
|
|
837
837
|
if (filesToPush.length > 0) {
|
|
838
|
-
// Push files to server (strip leading slash
|
|
838
|
+
// Push files to server (strip leading slash, server requires workspace-relative paths)
|
|
839
839
|
const uploadBatches = buildPushUploadBatches(filesToPush);
|
|
840
840
|
for (const batch of uploadBatches) {
|
|
841
841
|
result = await syncFiles(batch);
|
|
@@ -848,7 +848,7 @@ async function pushAtris() {
|
|
|
848
848
|
await emit('access_denied', { error_detail: detail });
|
|
849
849
|
process.exit(1);
|
|
850
850
|
}
|
|
851
|
-
// Permission denied
|
|
851
|
+
// Permission denied, retry with only team/ and journal/ files
|
|
852
852
|
const allowed = filesToPush.filter(f => f.path.startsWith('/team/') || f.path.startsWith('/journal/'));
|
|
853
853
|
skipped = filesToPush.filter(f => !f.path.startsWith('/team/') && !f.path.startsWith('/journal/'));
|
|
854
854
|
|
|
@@ -901,7 +901,7 @@ async function pushAtris() {
|
|
|
901
901
|
}
|
|
902
902
|
}
|
|
903
903
|
|
|
904
|
-
// Delete loop
|
|
904
|
+
// Delete loop, throttled, 429-aware, tracks per-file success/failure.
|
|
905
905
|
// Earlier bug: bulk deletes hit rate limit (60/min default) at request 60,
|
|
906
906
|
// then process.exit'd, leaving partial state and a manifest that thought
|
|
907
907
|
// everything was deleted. New behavior:
|
|
@@ -924,7 +924,7 @@ async function pushAtris() {
|
|
|
924
924
|
{ method: 'DELETE', token: creds.token }
|
|
925
925
|
);
|
|
926
926
|
if (deleteResult.status === 429) {
|
|
927
|
-
// Rate limit
|
|
927
|
+
// Rate limit, wait 20s, retry once
|
|
928
928
|
_rateLimitedDeletes++;
|
|
929
929
|
await new Promise((r) => setTimeout(r, 20000));
|
|
930
930
|
deleteResult = await apiRequestJson(
|
|
@@ -950,7 +950,7 @@ async function pushAtris() {
|
|
|
950
950
|
if (deleteFailed.length > 10) console.log(` ... +${deleteFailed.length - 10} more`);
|
|
951
951
|
}
|
|
952
952
|
|
|
953
|
-
// Display results
|
|
953
|
+
// Display results, only for files the server confirmed as landed.
|
|
954
954
|
// A non-technical user seeing "+ atris/ideas/foo.md new file" naturally
|
|
955
955
|
// assumes foo.md is on cloud. So we only print that line when the server
|
|
956
956
|
// actually confirmed it via per-file status. Anything else goes into the
|
|
@@ -965,12 +965,12 @@ async function pushAtris() {
|
|
|
965
965
|
for (const f of skipped) {
|
|
966
966
|
console.log(` - ${f.path.replace(/^\//, '')} skipped (no permission)`);
|
|
967
967
|
}
|
|
968
|
-
// Only print confirmed deletes (not failed ones
|
|
968
|
+
// Only print confirmed deletes (not failed ones, they were reported above)
|
|
969
969
|
for (const filePath of deletedConfirmed) {
|
|
970
970
|
console.log(` x ${filePath.replace(/^\//, '')} deleted`);
|
|
971
971
|
}
|
|
972
972
|
|
|
973
|
-
// Loud failure block
|
|
973
|
+
// Loud failure block, files the server silently dropped or rejected.
|
|
974
974
|
// These did NOT land on cloud even though the HTTP call returned 200.
|
|
975
975
|
if (failedToLand.length > 0) {
|
|
976
976
|
console.log('');
|
|
@@ -978,7 +978,7 @@ async function pushAtris() {
|
|
|
978
978
|
console.log(` dropped or rejected these files):`);
|
|
979
979
|
const shown = failedToLand.slice(0, 15);
|
|
980
980
|
for (const f of shown) {
|
|
981
|
-
const detail = f.error ?
|
|
981
|
+
const detail = f.error ? `, ${f.error}` : ` (${f.status})`;
|
|
982
982
|
console.log(` ✗ ${f.path.replace(/^\//, '')}${detail}`);
|
|
983
983
|
}
|
|
984
984
|
if (failedToLand.length > shown.length) {
|
|
@@ -1000,13 +1000,13 @@ async function pushAtris() {
|
|
|
1000
1000
|
if (skipped.length > 0) parts.push(`${skipped.length} skipped`);
|
|
1001
1001
|
console.log(` ${parts.join(', ')}.`);
|
|
1002
1002
|
|
|
1003
|
-
// Update manifest
|
|
1003
|
+
// Update manifest, mark pushed files with their new hash, drop ONLY confirmed deletes.
|
|
1004
1004
|
// Failed deletes stay in the manifest so the next push will retry them.
|
|
1005
1005
|
//
|
|
1006
1006
|
// CRITICAL: only record manifest entries for files the server confirmed as
|
|
1007
1007
|
// landed (landedPaths). If we recorded the local hash for a file that the
|
|
1008
1008
|
// server silently dropped, the next push would compare local==manifest and
|
|
1009
|
-
// skip it
|
|
1009
|
+
// skip it, the file would never land. Keeping it OUT of the manifest means
|
|
1010
1010
|
// the next push sees it as new/changed and retries automatically.
|
|
1011
1011
|
const updatedFiles = { ...baseFiles };
|
|
1012
1012
|
for (const f of filesToPush) {
|
|
@@ -1019,7 +1019,7 @@ async function pushAtris() {
|
|
|
1019
1019
|
}
|
|
1020
1020
|
saveManifest(resolvedSlug || slug, buildManifest(updatedFiles, null, { workspaceRoot: sourceDir }));
|
|
1021
1021
|
|
|
1022
|
-
// Telemetry
|
|
1022
|
+
// Telemetry, outcome reflects actual run quality, not just exit-code-zero.
|
|
1023
1023
|
// Partial delete failures or rate-limit retries mean the run was NOT a clean win;
|
|
1024
1024
|
// labeling them success would poison the RL signal.
|
|
1025
1025
|
const bytesChanged = filesToPush.reduce((acc, f) => acc + (f.content ? Buffer.byteLength(f.content, 'utf8') : 0), 0);
|
package/commands/rainmaker.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* atris rainmaker
|
|
4
|
+
* atris rainmaker, passthrough to atrisos-backend/scripts/rainmaker.py
|
|
5
5
|
*
|
|
6
6
|
* atris rainmaker # ASCII status dashboard
|
|
7
7
|
* atris rainmaker instinct # one morning opinion
|
package/commands/recap.js
CHANGED
|
@@ -160,14 +160,14 @@ function buildRecapData(root = process.cwd(), { days = DEFAULT_DAYS } = {}) {
|
|
|
160
160
|
function renderRecap(data) {
|
|
161
161
|
if (data.empty) {
|
|
162
162
|
return [
|
|
163
|
-
`RECAP
|
|
163
|
+
`RECAP: ${data.workspace}`,
|
|
164
164
|
'',
|
|
165
165
|
'No task history yet.',
|
|
166
166
|
'Run "atris init", then let Atris do one small job. Finished work will show up here with the checks that passed.',
|
|
167
167
|
].join('\n');
|
|
168
168
|
}
|
|
169
169
|
const lines = [];
|
|
170
|
-
lines.push(`RECAP
|
|
170
|
+
lines.push(`RECAP: ${data.workspace}, last ${data.days} day${data.days === 1 ? '' : 's'}`);
|
|
171
171
|
lines.push('');
|
|
172
172
|
lines.push('Plain English: what changed, how it was checked, and what still needs you.');
|
|
173
173
|
const headline = [];
|
|
@@ -179,7 +179,7 @@ function renderRecap(data) {
|
|
|
179
179
|
|
|
180
180
|
if (data.shipped.length) {
|
|
181
181
|
lines.push('');
|
|
182
|
-
lines.push(`DONE
|
|
182
|
+
lines.push(`DONE: ${data.shipped.length}`);
|
|
183
183
|
for (const t of data.shipped.slice(0, 12)) {
|
|
184
184
|
lines.push(` ${t.id} ${shortTitle(t.title)}`);
|
|
185
185
|
const check = plainCheck(t.proof);
|
|
@@ -190,7 +190,7 @@ function renderRecap(data) {
|
|
|
190
190
|
|
|
191
191
|
if (data.waiting.length) {
|
|
192
192
|
lines.push('');
|
|
193
|
-
lines.push(`NEEDS YOU
|
|
193
|
+
lines.push(`NEEDS YOU: ${data.waiting.length}`);
|
|
194
194
|
for (const t of data.waiting.slice(0, 10)) {
|
|
195
195
|
lines.push(` ${t.id} ${shortTitle(t.title)}`);
|
|
196
196
|
const check = plainCheck(t.proof);
|
|
@@ -202,7 +202,7 @@ function renderRecap(data) {
|
|
|
202
202
|
|
|
203
203
|
if (data.checking.length) {
|
|
204
204
|
lines.push('');
|
|
205
|
-
lines.push(`STILL BEING CHECKED
|
|
205
|
+
lines.push(`STILL BEING CHECKED: ${data.checking.length}`);
|
|
206
206
|
for (const t of data.checking.slice(0, 10)) {
|
|
207
207
|
lines.push(` ${t.id} ${shortTitle(t.title)}`);
|
|
208
208
|
}
|
|
@@ -211,7 +211,7 @@ function renderRecap(data) {
|
|
|
211
211
|
|
|
212
212
|
if (data.inProgress.length) {
|
|
213
213
|
lines.push('');
|
|
214
|
-
lines.push(`STILL WORKING
|
|
214
|
+
lines.push(`STILL WORKING: ${data.inProgress.length}`);
|
|
215
215
|
for (const t of data.inProgress) {
|
|
216
216
|
lines.push(` ${t.id} ${shortTitle(t.title)}${t.owner ? ` @${t.owner}` : ''}`);
|
|
217
217
|
}
|
|
@@ -224,7 +224,7 @@ function renderRecap(data) {
|
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
function renderShare(data) {
|
|
227
|
-
if (data.empty) return `Nothing to share yet on ${data.workspace}
|
|
227
|
+
if (data.empty) return `Nothing to share yet on ${data.workspace}, no finished tasks on record.`;
|
|
228
228
|
const lines = [];
|
|
229
229
|
lines.push(`What got done on ${data.workspace} in the last ${data.days} day${data.days === 1 ? '' : 's'}:`);
|
|
230
230
|
lines.push('');
|
package/commands/reel.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// atris reel
|
|
1
|
+
// atris reel, one line of text into a short, on-brand video (an animated card).
|
|
2
2
|
//
|
|
3
3
|
// atris reel "Ship faster" --theme brand --size square
|
|
4
4
|
// atris reel "It just works." --kind quote --by "a founder" --seconds 3
|
|
@@ -72,7 +72,7 @@ async function renderFrames(chrome, ts, spec, dir, w, h, onDone) {
|
|
|
72
72
|
async function run(argv) {
|
|
73
73
|
const { flags, pos } = parseFlags(argv);
|
|
74
74
|
if (pos[0] === 'help' || flags.help) {
|
|
75
|
-
console.log(`\n atris reel
|
|
75
|
+
console.log(`\n atris reel, one line of text into a short on-brand video\n
|
|
76
76
|
atris reel "Your headline" [--kind statement|quote|stat] [--theme <name>] [--size square|og|wide|story] [--seconds 2.6]
|
|
77
77
|
flags: --sub --kicker --by --number --label --brand --version --out <file.mp4>\n`);
|
|
78
78
|
return 0;
|
package/commands/release.js
CHANGED
|
@@ -48,7 +48,7 @@ async function releaseAtris({ dryRun = false } = {}) {
|
|
|
48
48
|
// 3. Build changelog
|
|
49
49
|
const changelog = commitLines.map(l => `- ${l}`).join('\n');
|
|
50
50
|
|
|
51
|
-
// 4. Determine bump type
|
|
51
|
+
// 4. Determine bump type: minor if any scorecard has reward >= 5, else patch
|
|
52
52
|
const bumpType = determineBumpType(cwd);
|
|
53
53
|
console.log(`bump type: ${bumpType}`);
|
|
54
54
|
|
|
@@ -104,7 +104,7 @@ async function releaseAtris({ dryRun = false } = {}) {
|
|
|
104
104
|
execFileSync('git', ['push', '--tags'], { cwd });
|
|
105
105
|
console.log('pushed');
|
|
106
106
|
} catch (err) {
|
|
107
|
-
console.log('push failed
|
|
107
|
+
console.log('push failed, you may need to push manually');
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
// 11. Create GitHub release via gh
|
|
@@ -115,7 +115,7 @@ async function releaseAtris({ dryRun = false } = {}) {
|
|
|
115
115
|
], { cwd });
|
|
116
116
|
console.log(`github release created: v${nextVersion}`);
|
|
117
117
|
} catch (err) {
|
|
118
|
-
console.log('gh release create failed
|
|
118
|
+
console.log('gh release create failed, install gh or create release manually');
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
// 12. Draft launch post
|
package/commands/report.js
CHANGED
|
@@ -39,7 +39,7 @@ function timestampMs(value) {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
function inlineText(value, fallback = 'untitled') {
|
|
42
|
-
const text = String(value || '').replace(/[
|
|
42
|
+
const text = String(value || '').replace(/[\u2014\u2013]/g, '-').replace(/\s+/g, ' ').trim();
|
|
43
43
|
return text || fallback;
|
|
44
44
|
}
|
|
45
45
|
|
package/commands/review.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Atris Review
|
|
2
|
+
* Atris Review: run code review with specialist agents
|
|
3
3
|
*
|
|
4
|
-
* atris review
|
|
5
|
-
* atris review <file>
|
|
6
|
-
* atris review --diff HEAD~1
|
|
7
|
-
* atris review --all
|
|
4
|
+
* atris review : review staged changes
|
|
5
|
+
* atris review <file> : review a specific file
|
|
6
|
+
* atris review --diff HEAD~1 : review last commit
|
|
7
|
+
* atris review --all : audit all Python services
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
const fs = require('fs');
|
package/commands/revisions.js
CHANGED
package/commands/run.js
CHANGED
|
@@ -381,7 +381,7 @@ async function runAtris(options = {}) {
|
|
|
381
381
|
process.exit(1);
|
|
382
382
|
}
|
|
383
383
|
|
|
384
|
-
// Check configured runner CLI is available. Dry runs preview context only
|
|
384
|
+
// Check configured runner CLI is available. Dry runs preview context only,
|
|
385
385
|
// they must work on machines (and CI) without the runner installed.
|
|
386
386
|
if (!dryRun) {
|
|
387
387
|
try {
|
package/commands/scout.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// atris scout
|
|
1
|
+
// atris scout: dispatch cheap Haiku subagents for search/context questions.
|
|
2
2
|
// Mirrors Claude Code's built-in subagent pattern: read-only, bounded report,
|
|
3
3
|
// main session never pays for the exploration.
|
|
4
4
|
//
|
|
@@ -44,7 +44,7 @@ const ENGINES = {
|
|
|
44
44
|
try {
|
|
45
45
|
const j = JSON.parse(out);
|
|
46
46
|
if (j && typeof j.output === 'string') return j.ok === false ? `fast lane error: ${j.error || j.output}` : j.output.trim();
|
|
47
|
-
} catch (_) { /* not JSON
|
|
47
|
+
} catch (_) { /* not JSON, fall through to raw */ }
|
|
48
48
|
return out.trim();
|
|
49
49
|
},
|
|
50
50
|
},
|
|
@@ -138,7 +138,7 @@ async function scoutCommand(argv) {
|
|
|
138
138
|
|
|
139
139
|
function showHelp() {
|
|
140
140
|
console.log(`
|
|
141
|
-
atris scout
|
|
141
|
+
atris scout: cheap read-only subagents for search & context questions
|
|
142
142
|
|
|
143
143
|
usage:
|
|
144
144
|
atris scout "<question>" ["<question>" ...] parallel scouts, one per question
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// atris security-review
|
|
1
|
+
// atris security-review, deterministic secrets / PII / privacy scan (no LLM).
|
|
2
2
|
//
|
|
3
3
|
// "Is this workspace safe to commit, publish, or hand to an autonomous loop?"
|
|
4
4
|
// Answers it with facts: file:line + rule + severity. Exit 1 on a HIGH finding,
|
|
@@ -200,7 +200,7 @@ function securityReviewCommand(argv = []) {
|
|
|
200
200
|
if (!opts.quiet) {
|
|
201
201
|
console.log('\n ◉ atris security review');
|
|
202
202
|
if (!findings.length) {
|
|
203
|
-
console.log(`\n ✓ clean
|
|
203
|
+
console.log(`\n ✓ clean, no active secrets, PII, or sensitive files in ${raw.scanned} tracked file${raw.scanned === 1 ? '' : 's'}`);
|
|
204
204
|
if (result.suppressed) console.log(` ${result.suppressed} accepted finding${result.suppressed === 1 ? '' : 's'} suppressed by ${result.baseline.path}`);
|
|
205
205
|
console.log('');
|
|
206
206
|
return 0;
|
|
@@ -225,10 +225,10 @@ function securityReviewCommand(argv = []) {
|
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
// The landing: short, true, decision-ready. What you read after the overnight
|
|
228
|
-
// loop
|
|
228
|
+
// loop, the opposite of a finding dump.
|
|
229
229
|
function renderLanding(landing, threshold) {
|
|
230
230
|
const date = new Date().toISOString().slice(0, 10);
|
|
231
|
-
const L = ['', ` ✈ security landing
|
|
231
|
+
const L = ['', ` ✈ security landing, ${date}`, ''];
|
|
232
232
|
if (landing.cleared) {
|
|
233
233
|
L.push(` CLEARED TO SHIP no unresolved findings at the ${threshold.toUpperCase()} line`);
|
|
234
234
|
} else {
|
|
@@ -248,7 +248,7 @@ function renderLanding(landing, threshold) {
|
|
|
248
248
|
if (landing.open.length) {
|
|
249
249
|
L.push(' needs you:');
|
|
250
250
|
for (const f of landing.open.slice(0, 10)) {
|
|
251
|
-
L.push(` ${f.sev.toUpperCase().padEnd(8)} ${f.file}${f.line ? ':' + f.line : ''}
|
|
251
|
+
L.push(` ${f.sev.toUpperCase().padEnd(8)} ${f.file}${f.line ? ':' + f.line : ''}, ${f.why}`);
|
|
252
252
|
}
|
|
253
253
|
if (landing.open.length > 10) L.push(` … and ${landing.open.length - 10} more`);
|
|
254
254
|
} else {
|
|
@@ -268,7 +268,7 @@ function renderLanding(landing, threshold) {
|
|
|
268
268
|
}
|
|
269
269
|
|
|
270
270
|
function printRules() {
|
|
271
|
-
console.log('\n atris security-review
|
|
271
|
+
console.log('\n atris security-review, deterministic rules:\n');
|
|
272
272
|
for (const sev of SEVERITIES) {
|
|
273
273
|
for (const r of RULES.filter((rule) => rule.sev === sev)) {
|
|
274
274
|
console.log(` ${r.sev.toUpperCase().padEnd(8)} ${r.cat.padEnd(8)} ${r.id.padEnd(22)} ${r.why}`);
|
|
@@ -396,7 +396,7 @@ function installHook() {
|
|
|
396
396
|
|
|
397
397
|
function printHelp() {
|
|
398
398
|
console.log(`
|
|
399
|
-
atris security-review
|
|
399
|
+
atris security-review, deterministic secrets / PII / privacy scan (no LLM)
|
|
400
400
|
|
|
401
401
|
atris security-review scan git-tracked files (default)
|
|
402
402
|
atris security-review <path> scan a file or dir
|
package/commands/serve.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Atris Serve
|
|
2
|
+
* Atris Serve, make this directory a live AI Computer.
|
|
3
3
|
*
|
|
4
4
|
* atris serve Start the bridge in current directory
|
|
5
5
|
* atris serve --agent <agent_id> Bind to a specific agent
|
|
@@ -33,7 +33,7 @@ const { apiRequestJson, getApiBaseUrl } = require('../utils/api');
|
|
|
33
33
|
const HEARTBEAT_INTERVAL_MS = 30000;
|
|
34
34
|
const RECONNECT_DELAY_MS = 2000;
|
|
35
35
|
const MAX_RECONNECT_DELAY_MS = 30000;
|
|
36
|
-
// Bash commands are bounded to 10s
|
|
36
|
+
// Bash commands are bounded to 10s, long batches won't lock the CLI for hours
|
|
37
37
|
const BASH_TIMEOUT_MS = 10000;
|
|
38
38
|
// Hard size limits to prevent OOM on large payloads
|
|
39
39
|
const MAX_WRITE_BYTES = 10 * 1024 * 1024; // 10 MB
|
|
@@ -138,7 +138,7 @@ async function applyOp(workingDir, op) {
|
|
|
138
138
|
|
|
139
139
|
if (type === 'bash') {
|
|
140
140
|
// Execute bash in the working directory with a timeout.
|
|
141
|
-
// Note: This is a powerful op
|
|
141
|
+
// Note: This is a powerful op, only the session owner can dispatch it,
|
|
142
142
|
// AND the session must have been created with allow_bash=true.
|
|
143
143
|
try {
|
|
144
144
|
const stdout = execSync(op.command, {
|
|
@@ -206,10 +206,10 @@ function streamSession(token, sessionId, workingDir) {
|
|
|
206
206
|
return;
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
console.log(`● Bridge active
|
|
209
|
+
console.log(`● Bridge active, listening for ops on session ${sessionId.slice(0, 8)}...`);
|
|
210
210
|
|
|
211
211
|
// Ping watchdog: the server pings every ~30s. Silence past 3 intervals
|
|
212
|
-
// means the socket died without a FIN (server redeploy, NAT drop)
|
|
212
|
+
// means the socket died without a FIN (server redeploy, NAT drop),
|
|
213
213
|
// kill it so the outer loop reconnects/re-registers instead of zombieing.
|
|
214
214
|
let lastSeen = Date.now();
|
|
215
215
|
const watchdog = setInterval(() => {
|
|
@@ -222,7 +222,7 @@ function streamSession(token, sessionId, workingDir) {
|
|
|
222
222
|
|
|
223
223
|
// Registry check: a rolling deploy can leave this stream alive on an
|
|
224
224
|
// old instance while new instances answer API calls from an empty
|
|
225
|
-
// in-memory session store
|
|
225
|
+
// in-memory session store, pings keep flowing so the silence watchdog
|
|
226
226
|
// never fires, but dispatchers can't find us. Ask the registry
|
|
227
227
|
// directly; if it forgot this session, reconnect and re-register.
|
|
228
228
|
const registryCheck = setInterval(async () => {
|
|
@@ -311,7 +311,7 @@ async function serveAtris(options = {}) {
|
|
|
311
311
|
|
|
312
312
|
console.log('');
|
|
313
313
|
console.log('╭──────────────────────────────────────────╮');
|
|
314
|
-
console.log('│ ATRIS SERVE
|
|
314
|
+
console.log('│ ATRIS SERVE, Local AI Computer Bridge │');
|
|
315
315
|
console.log('╰──────────────────────────────────────────╯');
|
|
316
316
|
console.log('');
|
|
317
317
|
console.log(` 📁 Directory: ${workingDir}`);
|
|
@@ -376,7 +376,7 @@ async function serveAtris(options = {}) {
|
|
|
376
376
|
reconnectDelay = RECONNECT_DELAY_MS; // reset on clean disconnect
|
|
377
377
|
} catch (err) {
|
|
378
378
|
if (shuttingDown) break;
|
|
379
|
-
// Server restarts wipe the in-memory session store
|
|
379
|
+
// Server restarts wipe the in-memory session store, a dead session id
|
|
380
380
|
// 404s forever, so re-register instead of retrying the corpse.
|
|
381
381
|
if (/session not found|404/i.test(err.message || '')) {
|
|
382
382
|
try {
|
|
@@ -391,7 +391,7 @@ async function serveAtris(options = {}) {
|
|
|
391
391
|
});
|
|
392
392
|
if (result.ok && result.data && result.data.session_id) {
|
|
393
393
|
session = result.data;
|
|
394
|
-
console.log(` ✓ Session expired server-side
|
|
394
|
+
console.log(` ✓ Session expired server-side, re-registered as ${session.session_id}`);
|
|
395
395
|
reconnectDelay = RECONNECT_DELAY_MS;
|
|
396
396
|
continue;
|
|
397
397
|
}
|
package/commands/setup.js
CHANGED
|
@@ -117,7 +117,7 @@ async function setupAtris() {
|
|
|
117
117
|
return;
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
// Resolve selection
|
|
120
|
+
// Resolve selection: try number first, then slug match
|
|
121
121
|
let selected = null;
|
|
122
122
|
const num = parseInt(answer, 10);
|
|
123
123
|
if (!isNaN(num) && num >= 1 && num <= businesses.length) {
|
package/commands/sign.js
CHANGED
|
@@ -3,7 +3,7 @@ const path = require('path');
|
|
|
3
3
|
|
|
4
4
|
// atris sign: co-author trailer on every commit in an atris workspace.
|
|
5
5
|
// Installs a prepare-commit-msg hook that appends "Co-authored-by: Atris"
|
|
6
|
-
// when the repo has an atris/ folder
|
|
6
|
+
// when the repo has an atris/ folder, same credit line Claude and Cursor use.
|
|
7
7
|
// Idempotent and non-destructive: appends a marked block, removes only its own block.
|
|
8
8
|
|
|
9
9
|
const MARKER = '# atris co-author';
|
|
@@ -66,18 +66,18 @@ function signCommand(sub) {
|
|
|
66
66
|
const { hookPath, removed } = removeSignHook();
|
|
67
67
|
console.log(removed
|
|
68
68
|
? `\n ✓ atris co-author removed: ${rel(hookPath)}\n`
|
|
69
|
-
: `\n nothing to remove
|
|
69
|
+
: `\n nothing to remove, atris co-author is not installed\n`);
|
|
70
70
|
return 0;
|
|
71
71
|
}
|
|
72
72
|
if (sub === 'status') {
|
|
73
73
|
const { hookPath, installed } = signStatus();
|
|
74
74
|
console.log(installed
|
|
75
75
|
? `\n ✓ atris co-author is on: ${rel(hookPath)}\n every commit gets: ${TRAILER}\n`
|
|
76
|
-
: `\n atris co-author is off
|
|
76
|
+
: `\n atris co-author is off, run 'atris sign' to turn it on\n`);
|
|
77
77
|
return 0;
|
|
78
78
|
}
|
|
79
79
|
if (sub && sub !== 'on' && sub !== 'install') {
|
|
80
|
-
console.log(`\n atris sign
|
|
80
|
+
console.log(`\n atris sign: co-author trailer on every commit\n\n atris sign install the prepare-commit-msg hook\n atris sign off remove it\n atris sign status check whether it's installed\n\n While installed, any commit in a repo with an atris/ folder gets:\n ${TRAILER}\n`);
|
|
81
81
|
return 2;
|
|
82
82
|
}
|
|
83
83
|
const { hookPath, already } = installSignHook();
|
package/commands/signup.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// seam: `npm i -g atris && atris signup x && atris play`.
|
|
8
8
|
//
|
|
9
9
|
// The account is born inert by design (0 credits, no executing agent, external
|
|
10
|
-
// mail paid-gated)
|
|
10
|
+
// mail paid-gated), identity is free, capability is earned via AgentXP.
|
|
11
11
|
// Backend: backend/routers/agent_auth_router.py (POST /auth/agent/signup).
|
|
12
12
|
|
|
13
13
|
const crypto = require('crypto');
|
|
@@ -19,7 +19,7 @@ const { argsWantHelp, isHelpToken } = require('../lib/noninteractive');
|
|
|
19
19
|
// before spending a network round trip / a rate-limit slot.
|
|
20
20
|
const HANDLE_RE = /^[a-z0-9]{3,30}$/;
|
|
21
21
|
|
|
22
|
-
// Proof-of-work
|
|
22
|
+
// Proof-of-work: mirror the server (agent_auth_router.py). The signup endpoint
|
|
23
23
|
// requires a nonce whose sha256(prefix:handle:bucket:nonce) has DIFFICULTY_BITS
|
|
24
24
|
// leading zero bits. Bucket = current 5-min window. Solved locally (~1s) so
|
|
25
25
|
// signup stays a single call; this is the cost that makes mass-minting expensive.
|
|
@@ -79,7 +79,7 @@ async function signupCommand(args = []) {
|
|
|
79
79
|
const { token, email, user_id: userId } = res.data;
|
|
80
80
|
const identity = email || `${handle}@atrismail.com`;
|
|
81
81
|
saveCredentials(token, null, identity, userId || null, 'atrisos');
|
|
82
|
-
console.log(`\n✓ You're in
|
|
82
|
+
console.log(`\n✓ You're in: ${identity}`);
|
|
83
83
|
console.log(' Inert starter account (0 credits): identity is free, capability is earned.');
|
|
84
84
|
console.log(' Saved to your active profile.');
|
|
85
85
|
console.log('\nNext:');
|
|
@@ -88,7 +88,7 @@ async function signupCommand(args = []) {
|
|
|
88
88
|
return 0;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
// Friendly, actionable errors
|
|
91
|
+
// Friendly, actionable errors, no stack traces for expected cases.
|
|
92
92
|
if (res.status === 409) {
|
|
93
93
|
console.error(`✗ "${handle}" is already taken or reserved. Try a different handle.`);
|
|
94
94
|
return 1;
|
package/commands/site.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
// atris site
|
|
1
|
+
// atris site, turn a folder of markdown (docs, your wiki, memory) into a
|
|
2
2
|
// beautiful, navigable static site in the design system. Built on lib/site.js.
|
|
3
3
|
//
|
|
4
4
|
// atris site <dir|doc.md> [--out dist] [--theme atris|terminal|paper] [--title T] [--serve]
|
|
5
|
+
// atris site publish <dir> --slug <slug> [--profile strict|app] [--spa] [--no-claim] [--build] [--json]
|
|
5
6
|
|
|
6
7
|
const { buildSite, serveSite } = require('../lib/site');
|
|
7
8
|
const { hasFlag } = require('../lib/arg-parser');
|
|
@@ -9,6 +10,9 @@ const { hasFlag } = require('../lib/arg-parser');
|
|
|
9
10
|
function flag(argv, name) { const i = argv.indexOf(name); return i !== -1 ? argv[i + 1] : null; }
|
|
10
11
|
|
|
11
12
|
async function run(argv) {
|
|
13
|
+
if (argv[0] === 'publish') {
|
|
14
|
+
return require('../lib/site-publish').run(argv.slice(1));
|
|
15
|
+
}
|
|
12
16
|
if (argv[0] === 'deploy') {
|
|
13
17
|
return require('./site-deploy').run(argv.slice(1));
|
|
14
18
|
}
|
|
@@ -20,14 +24,15 @@ async function run(argv) {
|
|
|
20
24
|
|
|
21
25
|
atris site <dir|doc.md> [--out dist] [--theme atris|terminal|paper] [--title T]
|
|
22
26
|
atris site atris/wiki --title "Atris Wiki" --serve
|
|
27
|
+
atris site publish <dir> --slug <slug> [--profile strict|app] [--spa] [--no-claim] [--build] [--json]
|
|
23
28
|
atris site deploy <dir> --name <slug> [--spa] [--dry-run] --yes
|
|
24
29
|
atris site deploy <dir> --fullstack --name <slug> [--dry-run] --yes
|
|
25
30
|
|
|
26
31
|
Each .md becomes a page; an index links them all. Same anti-slop design system,
|
|
27
32
|
semantic data-atris-block sections, ready for the web app. --serve previews it.
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
server with
|
|
34
|
+
publish uploads any built web folder through the hosted-sites api. deploy is
|
|
35
|
+
the older site setup flow; --fullstack deploys a node server with render.
|
|
31
36
|
`);
|
|
32
37
|
return input === 'help' || hasFlag(argv, '--help') ? 0 : 2;
|
|
33
38
|
}
|