atris 3.12.0 → 3.13.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/README.md +13 -12
- package/atris/skills/atris-feedback/SKILL.md +108 -0
- package/bin/atris.js +22 -11
- package/commands/business.js +124 -21
- package/commands/computer.js +145 -6
- package/commands/errors.js +155 -0
- package/commands/feedback.js +223 -71
- package/commands/proof.js +115 -0
- package/commands/pull.js +4 -2
- package/commands/push.js +6 -0
- package/commands/visualize.js +324 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ Then read the workspace's `atris/atris.md` and follow it exactly. `atris.md` is
|
|
|
27
27
|
|
|
28
28
|
| File | Purpose |
|
|
29
29
|
|------|---------|
|
|
30
|
-
| `atris/atris.md` |
|
|
30
|
+
| `atris/atris.md` | Main instructions for agents working in this repo |
|
|
31
31
|
| `atris/MAP.md` | Navigation index with file:line refs |
|
|
32
32
|
| `atris/TODO.md` | Shared task queue |
|
|
33
33
|
| `atris/logs/YYYY/YYYY-MM-DD.md` | Daily log, inbox, notes, completions |
|
|
@@ -67,7 +67,7 @@ atris
|
|
|
67
67
|
|
|
68
68
|
`atris init` scaffolds the workspace, including `atris/wiki/`. `atris` loads context and hands the workflow off to `atris/atris.md`.
|
|
69
69
|
|
|
70
|
-
If you're still shaping the idea, use `atris brainstorm`. If you want Atris to keep cycling, use `atris run` or `atris autopilot`. If you want
|
|
70
|
+
If you're still shaping the idea, use `atris brainstorm`. If you want Atris to keep cycling, use `atris run` or `atris autopilot`. If you want project memory checked for stale pages and missing context, use `atris loop`. `atris activate` surfaces wiki state from `atris/wiki/STATUS.md` when it exists.
|
|
71
71
|
|
|
72
72
|
Core loop: `plan` -> `do` -> `review`
|
|
73
73
|
|
|
@@ -84,9 +84,9 @@ atris business onboard --website https://blondish.world --contact "Joel Zimmerma
|
|
|
84
84
|
atris align --fix
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
That creates the cloud business, writes `.atris/business.json`, initializes `.atris/state/` for events
|
|
87
|
+
That creates the cloud business, writes `.atris/business.json`, initializes `.atris/state/` for events and run history, and scaffolds the local `atris/` workspace under `~/arena/atris-business/<slug>/` with starter roles, a default recap template, and an initial task queue in `atris/TODO.md`.
|
|
88
88
|
|
|
89
|
-
If you do not have a neat source pack yet, `atris business onboard` is the
|
|
89
|
+
If you do not have a neat source pack yet, `atris business onboard` is the easiest intake step: give it a website, a named human, a few notes, or run it in a folder with loose files. Atris turns that into raw intake, a starter brief, a first workflow, a safe next action, and a short operator brief.
|
|
90
90
|
|
|
91
91
|
You can also use bare input:
|
|
92
92
|
|
|
@@ -120,26 +120,27 @@ atris business record atris/reports/2026-04-12-operator-recap.md --outcome mixed
|
|
|
120
120
|
| `atris ingest` | Stage raw evidence into `atris/context/` and compile into `atris/wiki/` |
|
|
121
121
|
| `atris loop` | Refresh wiki health, stale/orphan signals, and next ingest candidates |
|
|
122
122
|
| `atris wiki` | Full wiki namespace: ingest, query, lint, search, log, and loop |
|
|
123
|
-
| `atris
|
|
123
|
+
| `atris receipt` | Save evidence from an agent run |
|
|
124
|
+
| `atris experiments` | Run small experiments and compare results |
|
|
124
125
|
|
|
125
126
|
## Built-In Systems
|
|
126
127
|
|
|
127
128
|
- `atris learn` stores structured project memory in `atris/learnings.jsonl`
|
|
128
129
|
- `atris wiki` keeps repo memory in `atris/wiki/` by default, with `--cloud` when you want the remote workspace path
|
|
129
130
|
- `atris ingest` now stages local source packs under `atris/context/_ingest/`, writes a manifest receipt, and refreshes `atris/wiki/STATUS.md` plus `log.md`
|
|
130
|
-
- `atris wiki --private`
|
|
131
|
+
- `atris wiki --private` stores local-only sensitive notes under `.atris/presidio/`
|
|
131
132
|
- `atris loop` refreshes `atris/wiki/STATUS.md` and `atris/wiki/log.md`, flags stale/orphan pages, and suggests the next ingest
|
|
132
133
|
- `atris activate` loads the current wiki status so the next session starts with project memory, not just tasks
|
|
133
|
-
- `atris experiments` runs
|
|
134
|
+
- `atris experiments` runs small test packs in `atris/experiments/`
|
|
134
135
|
- `atris pull` and `atris push` sync cloud workspaces and journals
|
|
135
136
|
|
|
136
137
|
## Verifiable Feedback Loop
|
|
137
138
|
|
|
138
139
|
Under the hood, Atris can keep score on real repo work.
|
|
139
140
|
|
|
140
|
-
-
|
|
141
|
-
- `atris autopilot` can run that check after review
|
|
142
|
-
- Future
|
|
141
|
+
- Tasks can carry a `Verify:` command, so work can end on a deterministic check instead of pure prose.
|
|
142
|
+
- `atris autopilot` can run that check after review and record the result in the journal.
|
|
143
|
+
- Future task picks can use recent results, so Atris learns from repo-local history without claiming model retraining.
|
|
143
144
|
|
|
144
145
|
## Benchmark Harness
|
|
145
146
|
|
|
@@ -167,7 +168,7 @@ What to inspect:
|
|
|
167
168
|
- receipts land in `atris/experiments/endstate-baseline/artifacts/` and
|
|
168
169
|
`atris/experiments/endstate-stack/artifacts/`
|
|
169
170
|
- scores append to each pack's `results.tsv`
|
|
170
|
-
- `atris experiments compare endstate` prints the latest side-by-side
|
|
171
|
+
- `atris experiments compare endstate` prints the latest side-by-side comparison
|
|
171
172
|
- `atris experiments replay endstate` runs the full public dry-run rehearsal
|
|
172
173
|
- the benchmark contract lives at `atris/features/endstate/contract.md`
|
|
173
174
|
- the verification log lives at `atris/features/endstate/validate.md`
|
|
@@ -198,7 +199,7 @@ For Codex, copy any skill folder into `~/.codex/skills/`.
|
|
|
198
199
|
## v3.2.0
|
|
199
200
|
|
|
200
201
|
- **Staleness gate** — tasks tagged `[unverified]` are skipped at the moment of use, not pruned eagerly. Three-state model: actionable / unverified / deleted.
|
|
201
|
-
- **Lesson gate** — `isLessonResolved` checks whether a lesson already shipped before proposing new
|
|
202
|
+
- **Lesson gate** — `isLessonResolved` checks whether a lesson already shipped before proposing new work from it. Prevents the loop from re-solving solved problems.
|
|
202
203
|
- **`atris release`** — new command: tags the version, bumps package.json, creates a GitHub release, and drafts a `/launch` post in one shot.
|
|
203
204
|
- **Shell injection fix** — `checkStaleness` switched from `execSync` string interpolation to `execFileSync` with args arrays. Markdown-derived content (task titles, inbox items) no longer reaches a shell.
|
|
204
205
|
- **Codex hardening** — `atris activate` and `atris` entry point detect Codex environments and write `AGENTS.md` so Codex sessions start with workspace context.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: atris-feedback
|
|
3
|
+
description: Submit, list, resolve, close, or delete Atris customer feedback. Use when user types /feedback or asks to triage the feedback queue.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
tags:
|
|
6
|
+
- feedback
|
|
7
|
+
- customer
|
|
8
|
+
- admin
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Feedback
|
|
12
|
+
|
|
13
|
+
One skill for everything: submit feedback, view the queue, resolve/close/delete items.
|
|
14
|
+
|
|
15
|
+
## Parse the input
|
|
16
|
+
|
|
17
|
+
- `/feedback` (no args) → show the queue
|
|
18
|
+
- `/feedback <message>` → submit new feedback
|
|
19
|
+
- `/feedback resolve <id> <resolution>` → mark as resolved, notify customer
|
|
20
|
+
- `/feedback close <id>` → close as wontfix/duplicate
|
|
21
|
+
- `/feedback delete <id>` → remove from queue
|
|
22
|
+
|
|
23
|
+
## Preferred path: the Atris CLI
|
|
24
|
+
|
|
25
|
+
The `atris` CLI wraps every feedback operation against the production API and
|
|
26
|
+
handles auth from the user's login. Use it first — it's the canonical,
|
|
27
|
+
audited path and works without needing AWS credentials.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
atris feedback # list queue
|
|
31
|
+
atris feedback "the calendar hangs" # submit
|
|
32
|
+
atris feedback resolve abc123 "fixed" # mark resolved
|
|
33
|
+
atris feedback close abc123 # close as wontfix
|
|
34
|
+
atris feedback delete abc123 # delete
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
IDs can be short (first 8 chars of the UUID) — the CLI resolves the prefix
|
|
38
|
+
against the live list before acting.
|
|
39
|
+
|
|
40
|
+
If `atris` is not on PATH, it lives at `~/arena/atris-cli/bin/atris.js`.
|
|
41
|
+
|
|
42
|
+
## Fallback: direct API / DynamoDB
|
|
43
|
+
|
|
44
|
+
Only use this path if the CLI is unavailable (stale install, broken login).
|
|
45
|
+
|
|
46
|
+
### Setup
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
cd ~/arena/atrisos-backend && source venv/bin/activate
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from dotenv import load_dotenv; load_dotenv('backend/.env')
|
|
54
|
+
import boto3
|
|
55
|
+
table = boto3.resource('dynamodb', region_name='us-east-1').Table('atris_feedback')
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Submit
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
curl -s -X POST "https://api.atris.ai/api/feedback" \
|
|
62
|
+
-H "Content-Type: application/json" \
|
|
63
|
+
-H "X-Feedback-Key: $FEEDBACK_API_KEY" \
|
|
64
|
+
-d '{"message": "THE_MESSAGE", "source": "cli", "context": {"user_email": "GIT_EMAIL"}}'
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Confirm: `Feedback submitted (id: abc123)`
|
|
68
|
+
|
|
69
|
+
### Resolve
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
table.update_item(
|
|
73
|
+
Key={'id': FULL_ID},
|
|
74
|
+
UpdateExpression='SET #s = :s, resolution = :r, resolved_at = :t',
|
|
75
|
+
ExpressionAttributeNames={'#s': 'status'},
|
|
76
|
+
ExpressionAttributeValues={':s': 'resolved', ':r': RESOLUTION, ':t': NOW},
|
|
77
|
+
)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Print: `Resolved abc123: <resolution>`
|
|
81
|
+
|
|
82
|
+
### Close
|
|
83
|
+
|
|
84
|
+
Same as resolve but `status = 'closed'`, no resolution text needed.
|
|
85
|
+
|
|
86
|
+
### Delete
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
table.delete_item(Key={'id': FULL_ID})
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Print: `Deleted abc123`
|
|
93
|
+
|
|
94
|
+
### ID matching
|
|
95
|
+
|
|
96
|
+
Users type short IDs (first 8 chars). Scan the table and match by prefix
|
|
97
|
+
to find the full UUID.
|
|
98
|
+
|
|
99
|
+
## Security
|
|
100
|
+
|
|
101
|
+
- NEVER include API keys, tokens, or secrets in feedback messages
|
|
102
|
+
- Server-side sanitization strips them anyway (double protection)
|
|
103
|
+
- Max 2000 chars per message
|
|
104
|
+
|
|
105
|
+
## Output
|
|
106
|
+
|
|
107
|
+
Always print the result directly as text. Never leave it inside a tool
|
|
108
|
+
call expansion.
|
package/bin/atris.js
CHANGED
|
@@ -247,7 +247,7 @@ function showHelp() {
|
|
|
247
247
|
console.log('Optional helpers:');
|
|
248
248
|
console.log(' brainstorm - Explore ideas conversationally before planning');
|
|
249
249
|
console.log(' autopilot - Guided loop that can clarify TODOs and run plan → do → review');
|
|
250
|
-
console.log(' visualize -
|
|
250
|
+
console.log(' visualize - Generate a Slack/deck-ready visual from a prompt');
|
|
251
251
|
console.log('');
|
|
252
252
|
console.log('Experiments:');
|
|
253
253
|
console.log(' experiments init [slug] - Prepare atris/experiments/ or scaffold a pack');
|
|
@@ -272,7 +272,7 @@ function showHelp() {
|
|
|
272
272
|
console.log(' wake [business] - Resume workspace (agents restart)');
|
|
273
273
|
console.log('');
|
|
274
274
|
console.log('Business:');
|
|
275
|
-
console.log(' business init <name> -
|
|
275
|
+
console.log(' business init <name> - RECOMMENDED: create business environment (cloud + local)');
|
|
276
276
|
console.log(' business onboard - Onboard from sparse input (--name, --website, --contact)');
|
|
277
277
|
console.log(' business add <slug> - Connect a business');
|
|
278
278
|
console.log(' business list - Show connected businesses');
|
|
@@ -280,7 +280,7 @@ function showHelp() {
|
|
|
280
280
|
console.log(' business team [slug] - Show members, roles, and admin access');
|
|
281
281
|
console.log(' business health <slug> - Health report (members, workspace, issues)');
|
|
282
282
|
console.log(' business audit - One-line health summary of all businesses');
|
|
283
|
-
console.log(' business create <name> -
|
|
283
|
+
console.log(' business create <name> - Cloud-only business record; add --workspace to also scaffold local');
|
|
284
284
|
console.log(' business connect <svc> - Wire a skill/integration');
|
|
285
285
|
console.log(' business notify <mode> - Set notification mode (digest/silent/push)');
|
|
286
286
|
console.log(' business deploy <slug> - Push local business to cloud');
|
|
@@ -291,6 +291,7 @@ function showHelp() {
|
|
|
291
291
|
console.log('');
|
|
292
292
|
console.log('Cloud & agents:');
|
|
293
293
|
console.log(' computer - Talk directly to the AI computer (bash or agent exec)');
|
|
294
|
+
console.log(' receipt - Save evidence from an agent run');
|
|
294
295
|
console.log(' console - Start/attach always-on coding console (tmux daemon)');
|
|
295
296
|
console.log(' agent - Select which Atris agent to use');
|
|
296
297
|
console.log(' chat - Chat with the selected Atris agent');
|
|
@@ -328,8 +329,11 @@ function showHelp() {
|
|
|
328
329
|
console.log(' plugin info - Preview what will be included');
|
|
329
330
|
console.log('');
|
|
330
331
|
console.log('Feedback:');
|
|
331
|
-
console.log(' feedback "msg"
|
|
332
|
-
console.log(' feedback
|
|
332
|
+
console.log(' feedback "msg" - Submit feedback');
|
|
333
|
+
console.log(' feedback - List feedback queue');
|
|
334
|
+
console.log(' feedback resolve <id> "<note>" - Mark resolved (admin)');
|
|
335
|
+
console.log(' feedback close <id> - Close as wontfix (admin)');
|
|
336
|
+
console.log(' feedback delete <id> - Delete feedback (admin)');
|
|
333
337
|
console.log('');
|
|
334
338
|
console.log('Other:');
|
|
335
339
|
console.log(' version - Show Atris version');
|
|
@@ -429,10 +433,10 @@ const { planAtris: planCmd, doAtris: doCmd, reviewAtris: reviewCmd } = require('
|
|
|
429
433
|
// Check if this is a known command or natural language input
|
|
430
434
|
const knownCommands = ['init', 'log', 'status', 'analytics', 'visualize', 'brainstorm', 'autopilot', 'run', 'plan', 'do', 'review', 'release',
|
|
431
435
|
'activate', '_activate', 'agent', 'chat', 'console', 'login', 'logout', 'whoami', 'switch', 'use', 'accounts', '_resolve', '_profile-email', '_switch-session', 'shell-init', 'update', 'upgrade', 'version', 'help', 'next', 'atris',
|
|
432
|
-
'clean', 'verify', 'search', 'skill', 'member', 'app', 'learn', 'plugin', 'experiments', 'pull', 'push', 'align', 'terminal', 'computer', 'diff', 'business', 'sync',
|
|
436
|
+
'clean', 'verify', 'search', 'skill', 'member', 'app', 'learn', 'plugin', 'experiments', 'receipt', 'proof', 'openclaw', 'pull', 'push', 'align', 'terminal', 'computer', 'diff', 'business', 'sync',
|
|
433
437
|
'ingest', 'query', 'lint', 'loop',
|
|
434
438
|
'gmail', 'calendar', 'twitter', 'slack', 'integrations', 'setup', 'clean-workspace', 'cw',
|
|
435
|
-
'fork', 'browse', 'publish', 'sleep', 'wake', 'feedback', 'wiki', 'code-review', 'cr', 'soul', 'fleet'];
|
|
439
|
+
'fork', 'browse', 'publish', 'sleep', 'wake', 'feedback', 'errors', 'wiki', 'code-review', 'cr', 'soul', 'fleet'];
|
|
436
440
|
|
|
437
441
|
// Check if command is an atris.md spec file - triggers welcome visualization
|
|
438
442
|
function isSpecFile(cmd) {
|
|
@@ -865,10 +869,9 @@ if (command === 'init') {
|
|
|
865
869
|
} else if (command === 'shell-init') {
|
|
866
870
|
require('../commands/auth').shellInit();
|
|
867
871
|
} else if (command === 'visualize') {
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
require('../commands/visualize').visualizeAtris();
|
|
872
|
+
require('../commands/visualize').visualizeAtris(process.argv.slice(3))
|
|
873
|
+
.then(() => process.exit(0))
|
|
874
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
872
875
|
} else if (command === 'run') {
|
|
873
876
|
const args = process.argv.slice(3);
|
|
874
877
|
if (args.includes('--help') || args.includes('-h')) {
|
|
@@ -1157,6 +1160,10 @@ if (command === 'init') {
|
|
|
1157
1160
|
const subcommand = process.argv[3];
|
|
1158
1161
|
const args = process.argv.slice(4);
|
|
1159
1162
|
require('../commands/experiments').experimentsCommand(subcommand, ...args);
|
|
1163
|
+
} else if (command === 'receipt' || command === 'proof' || command === 'openclaw') {
|
|
1164
|
+
const subcommand = process.argv[3];
|
|
1165
|
+
const args = process.argv.slice(4);
|
|
1166
|
+
require('../commands/proof').proofCommand(subcommand, ...args);
|
|
1160
1167
|
} else if (command === 'setup') {
|
|
1161
1168
|
require('../commands/setup').setupAtris()
|
|
1162
1169
|
.then(() => process.exit(0))
|
|
@@ -1185,6 +1192,10 @@ if (command === 'init') {
|
|
|
1185
1192
|
require('../commands/feedback').feedbackCommand()
|
|
1186
1193
|
.then(() => process.exit(0))
|
|
1187
1194
|
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1195
|
+
} else if (command === 'errors') {
|
|
1196
|
+
require('../commands/errors').errorsCommand()
|
|
1197
|
+
.then(() => process.exit(0))
|
|
1198
|
+
.catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
|
|
1188
1199
|
} else {
|
|
1189
1200
|
console.log(`Unknown command: ${command}`);
|
|
1190
1201
|
console.log('Run "atris help" to see available commands');
|
package/commands/business.js
CHANGED
|
@@ -13,6 +13,20 @@ function getBusinessConfigPath() {
|
|
|
13
13
|
return path.join(dir, 'businesses.json');
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
function slugify(name) {
|
|
17
|
+
return String(name || '')
|
|
18
|
+
.toLowerCase()
|
|
19
|
+
.trim()
|
|
20
|
+
.replace(/[^a-z0-9\s-]/g, '')
|
|
21
|
+
.replace(/\s+/g, '-')
|
|
22
|
+
.replace(/-+/g, '-')
|
|
23
|
+
.replace(/^-+|-+$/g, '');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function isHelpToken(arg) {
|
|
27
|
+
return arg === '--help' || arg === '-h' || arg === 'help' || arg === '-?';
|
|
28
|
+
}
|
|
29
|
+
|
|
16
30
|
function loadBusinesses() {
|
|
17
31
|
const p = getBusinessConfigPath();
|
|
18
32
|
if (!fs.existsSync(p)) return {};
|
|
@@ -774,7 +788,45 @@ function detectBusinessSlug(explicitSlug) {
|
|
|
774
788
|
}
|
|
775
789
|
}
|
|
776
790
|
|
|
791
|
+
async function findExistingBusinessBySlug(slug, token) {
|
|
792
|
+
if (!slug) return null;
|
|
793
|
+
|
|
794
|
+
// Local cache first — no network round-trip needed.
|
|
795
|
+
const local = loadBusinesses();
|
|
796
|
+
if (local[slug]) {
|
|
797
|
+
return { id: local[slug].business_id, name: local[slug].name, slug, source: 'local' };
|
|
798
|
+
}
|
|
799
|
+
for (const v of Object.values(local)) {
|
|
800
|
+
if (v && v.slug === slug) {
|
|
801
|
+
return { id: v.business_id, name: v.name, slug, source: 'local' };
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
if (!token) return null;
|
|
806
|
+
|
|
807
|
+
// Cloud lookup — covers businesses the user is a member of but hasn't added.
|
|
808
|
+
const direct = await apiRequestJson(`/business/by-slug/${encodeURIComponent(slug)}`, {
|
|
809
|
+
method: 'GET',
|
|
810
|
+
token,
|
|
811
|
+
});
|
|
812
|
+
if (direct.ok && direct.data && direct.data.id) {
|
|
813
|
+
return { id: direct.data.id, name: direct.data.name, slug: direct.data.slug || slug, source: 'cloud' };
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
const list = await apiRequestJson('/business/', { method: 'GET', token });
|
|
817
|
+
if (list.ok && Array.isArray(list.data)) {
|
|
818
|
+
const match = list.data.find(b => b && b.slug === slug);
|
|
819
|
+
if (match) return { id: match.id, name: match.name, slug: match.slug, source: 'cloud' };
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
return null;
|
|
823
|
+
}
|
|
824
|
+
|
|
777
825
|
async function addBusiness(slug) {
|
|
826
|
+
if (!slug || isHelpToken(slug)) {
|
|
827
|
+
console.error('Usage: atris business add <slug>');
|
|
828
|
+
process.exit(1);
|
|
829
|
+
}
|
|
778
830
|
if (!slug) {
|
|
779
831
|
console.error('Usage: atris business add <slug>');
|
|
780
832
|
process.exit(1);
|
|
@@ -1008,7 +1060,7 @@ function listBusinessesLocal(opts = {}) {
|
|
|
1008
1060
|
}
|
|
1009
1061
|
|
|
1010
1062
|
async function removeBusiness(slug) {
|
|
1011
|
-
if (!slug) {
|
|
1063
|
+
if (!slug || isHelpToken(slug)) {
|
|
1012
1064
|
console.error('Usage: atris business remove <slug>');
|
|
1013
1065
|
process.exit(1);
|
|
1014
1066
|
}
|
|
@@ -1262,8 +1314,11 @@ async function businessAudit() {
|
|
|
1262
1314
|
}
|
|
1263
1315
|
|
|
1264
1316
|
async function createBusinessInternal(name, flags = [], mode = 'auto') {
|
|
1265
|
-
if (!name) {
|
|
1317
|
+
if (!name || isHelpToken(name) || String(name).startsWith('-')) {
|
|
1266
1318
|
console.error('Usage: atris business create <name> [--description "..."] [--workspace] [--here|--root <dir>]');
|
|
1319
|
+
if (name && String(name).startsWith('-') && !isHelpToken(name)) {
|
|
1320
|
+
console.error(`\n Refusing to create a business named "${name}" — looks like a flag, not a name.`);
|
|
1321
|
+
}
|
|
1267
1322
|
process.exit(1);
|
|
1268
1323
|
}
|
|
1269
1324
|
|
|
@@ -1275,6 +1330,29 @@ async function createBusinessInternal(name, flags = [], mode = 'auto') {
|
|
|
1275
1330
|
|
|
1276
1331
|
const options = parseCreateBusinessFlags(flags);
|
|
1277
1332
|
const description = options.description;
|
|
1333
|
+
const force = flags.includes('--force') || flags.includes('--allow-duplicate');
|
|
1334
|
+
|
|
1335
|
+
// Pre-flight: refuse to create a duplicate by slug. The backend will silently
|
|
1336
|
+
// suffix `-1`, `-2`, etc., which produces ghost businesses when users actually
|
|
1337
|
+
// wanted to attach to an existing one. Guide them to `atris pull` instead.
|
|
1338
|
+
if (!force) {
|
|
1339
|
+
const desiredSlug = slugify(name);
|
|
1340
|
+
if (desiredSlug) {
|
|
1341
|
+
const existing = await findExistingBusinessBySlug(desiredSlug, creds.token);
|
|
1342
|
+
if (existing) {
|
|
1343
|
+
console.error(`\nA business with slug "${desiredSlug}" already exists.`);
|
|
1344
|
+
console.error(` Name: ${existing.name || desiredSlug}`);
|
|
1345
|
+
if (existing.id) console.error(` ID: ${existing.id}`);
|
|
1346
|
+
console.error('');
|
|
1347
|
+
console.error('To set up a local workspace for it, run:');
|
|
1348
|
+
console.error(` atris pull ${desiredSlug} # into ./${desiredSlug}`);
|
|
1349
|
+
console.error(` atris pull ${desiredSlug} --into <path> # into a custom path`);
|
|
1350
|
+
console.error('');
|
|
1351
|
+
console.error(`To create a NEW business anyway (will be slugged "${desiredSlug}-1"), pass --force.`);
|
|
1352
|
+
process.exit(1);
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1278
1356
|
|
|
1279
1357
|
console.log(`Creating business: ${name}...`);
|
|
1280
1358
|
|
|
@@ -1832,12 +1910,52 @@ async function quickstart() {
|
|
|
1832
1910
|
(get 1 email/day instead of every notification)
|
|
1833
1911
|
|
|
1834
1912
|
Templates: saas, agency, ecommerce, content, restaurant
|
|
1913
|
+
|
|
1914
|
+
Rule of thumb:
|
|
1915
|
+
atris business init "<name>" = cloud + local business computer workspace
|
|
1916
|
+
atris business create "<name>" = cloud-only unless you pass --workspace
|
|
1835
1917
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
1836
1918
|
`);
|
|
1837
1919
|
}
|
|
1838
1920
|
|
|
1839
1921
|
|
|
1922
|
+
function printBusinessHelp() {
|
|
1923
|
+
console.log('Usage: atris business <command> [args]');
|
|
1924
|
+
console.log('');
|
|
1925
|
+
console.log(' quickstart ← Start here! 3-command guide');
|
|
1926
|
+
console.log('');
|
|
1927
|
+
console.log(' init <name> RECOMMENDED: create a business environment (cloud + local)');
|
|
1928
|
+
console.log(' workspace <name> Alias for init');
|
|
1929
|
+
console.log(' create <name> Cloud-only business record; add --workspace to also scaffold local');
|
|
1930
|
+
console.log(' add <slug> Register an existing cloud business');
|
|
1931
|
+
console.log(' list Show registered businesses');
|
|
1932
|
+
console.log(' team [slug] Show members, roles, and admin access');
|
|
1933
|
+
console.log(' status <slug> Quick status check');
|
|
1934
|
+
console.log(' health [slug] Full health dashboard');
|
|
1935
|
+
console.log(' audit Audit all businesses');
|
|
1936
|
+
console.log(' connect <service> Connect a skill/integration');
|
|
1937
|
+
console.log(' notify <mode> Set notification mode (digest/silent/push)');
|
|
1938
|
+
console.log(' deploy <slug> Push local business to cloud');
|
|
1939
|
+
console.log(' onboard Seed brief, person, first loop, safe next action, and one-pager from sparse input');
|
|
1940
|
+
console.log(' record <report> Append recap state into events, episodes, and scorecards');
|
|
1941
|
+
console.log(' remove <slug> Unregister locally');
|
|
1942
|
+
console.log('');
|
|
1943
|
+
console.log(' Already-attached business? Run `atris pull <slug>` to scaffold a local workspace.');
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1840
1946
|
async function businessCommand(subcommand, ...args) {
|
|
1947
|
+
// Help intercept — without this, `atris business init --help` would treat
|
|
1948
|
+
// `--help` as a business name and create one. Same for any subcommand that
|
|
1949
|
+
// takes a positional name/slug.
|
|
1950
|
+
if (!subcommand || isHelpToken(subcommand)) {
|
|
1951
|
+
printBusinessHelp();
|
|
1952
|
+
return;
|
|
1953
|
+
}
|
|
1954
|
+
if (args.length > 0 && isHelpToken(args[0])) {
|
|
1955
|
+
printBusinessHelp();
|
|
1956
|
+
return;
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1841
1959
|
switch (subcommand) {
|
|
1842
1960
|
case 'add':
|
|
1843
1961
|
await addBusiness(args[0]);
|
|
@@ -1907,25 +2025,10 @@ async function businessCommand(subcommand, ...args) {
|
|
|
1907
2025
|
await quickstart();
|
|
1908
2026
|
break;
|
|
1909
2027
|
default:
|
|
1910
|
-
console.
|
|
1911
|
-
console.
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
console.log(' init <name> Create a business environment (cloud + local)');
|
|
1915
|
-
console.log(' workspace <name> Alias for init');
|
|
1916
|
-
console.log(' create <name> Create the cloud business; add --workspace for a local business environment');
|
|
1917
|
-
console.log(' add <slug> Register an existing cloud business');
|
|
1918
|
-
console.log(' list Show registered businesses');
|
|
1919
|
-
console.log(' team [slug] Show members, roles, and admin access');
|
|
1920
|
-
console.log(' status <slug> Quick status check');
|
|
1921
|
-
console.log(' health [slug] Full health dashboard');
|
|
1922
|
-
console.log(' audit Audit all businesses');
|
|
1923
|
-
console.log(' connect <service> Connect a skill/integration');
|
|
1924
|
-
console.log(' notify <mode> Set notification mode (digest/silent/push)');
|
|
1925
|
-
console.log(' deploy <slug> Push local business to cloud');
|
|
1926
|
-
console.log(' onboard Seed brief, person, first loop, safe next action, and one-pager from sparse input');
|
|
1927
|
-
console.log(' record <report> Append recap state into events, episodes, and scorecards');
|
|
1928
|
-
console.log(' remove <slug> Unregister locally');
|
|
2028
|
+
console.error(`Unknown subcommand: ${subcommand}`);
|
|
2029
|
+
console.error('');
|
|
2030
|
+
printBusinessHelp();
|
|
2031
|
+
process.exitCode = 1;
|
|
1929
2032
|
}
|
|
1930
2033
|
}
|
|
1931
2034
|
|