atris 3.37.1 → 3.40.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/AGENTS.md +25 -6
- package/README.md +2 -0
- package/atris/PERSONA.md +11 -11
- package/atris.md +17 -2
- package/ax +160 -34
- package/bin/atris.js +78 -6
- package/commands/activate.js +16 -3
- package/commands/agent-spawn.js +13 -18
- package/commands/autoland.js +76 -47
- package/commands/autopilot-front.js +0 -4
- package/commands/autopilot.js +0 -12
- package/commands/bench.js +10 -12
- package/commands/brain.js +0 -7
- package/commands/brief.js +0 -2
- package/commands/business-sync.js +0 -1
- package/commands/business.js +452 -12
- package/commands/chat-scan.js +5 -7
- package/commands/clean.js +31 -2
- package/commands/close.js +46 -11
- package/commands/cloud.js +0 -1
- package/commands/codex-goal.js +8 -12
- package/commands/computer.js +6 -5
- package/commands/console.js +64 -11
- package/commands/decide.js +166 -0
- package/commands/deck.js +30 -12
- package/commands/dream.js +0 -7
- package/commands/drill.js +14 -25
- package/commands/engine.js +206 -26
- package/commands/experiments.js +0 -4
- package/commands/fleet-report.js +12 -4
- package/commands/game.js +261 -0
- package/commands/gm.js +17 -7
- package/commands/goal.js +0 -6
- package/commands/harvest.js +1 -5
- package/commands/improve.js +29 -8
- package/commands/init.js +41 -37
- package/commands/integrations.js +0 -7
- package/commands/land.js +77 -20
- package/commands/launchpad.js +1 -16
- package/commands/lesson.js +17 -7
- package/commands/lifecycle.js +5 -5
- package/commands/log.js +55 -5
- package/commands/loop-front.js +0 -2
- package/commands/loops.js +6 -5
- package/commands/meet.js +0 -2
- package/commands/member.js +622 -573
- package/commands/mission.js +790 -314
- package/commands/next.js +0 -1
- package/commands/now.js +0 -12
- package/commands/one-lap.js +8 -8
- package/commands/orb.js +0 -4
- package/commands/pack-craft.js +0 -1
- package/commands/pack.js +3599 -424
- package/commands/play.js +6 -6
- package/commands/probe.js +12 -6
- package/commands/pulse.js +88 -64
- package/commands/push.js +0 -4
- package/commands/radar.js +14 -11
- package/commands/recover.js +340 -0
- package/commands/release.js +10 -9
- package/commands/report.js +0 -1
- package/commands/router.js +320 -0
- package/commands/run-front.js +0 -2
- package/commands/search.js +0 -3
- package/commands/site-deploy.js +870 -0
- package/commands/site.js +11 -2
- package/commands/skill.js +7 -2
- package/commands/slop.js +237 -7
- package/commands/status.js +6 -0
- package/commands/stream.js +4 -20
- package/commands/study.js +0 -3
- package/commands/sync-checkout.js +51 -0
- package/commands/sync.js +11 -40
- package/commands/task.js +999 -595
- package/commands/taste.js +101 -0
- package/commands/teach.js +86 -0
- package/commands/team.js +83 -3
- package/commands/unknowns.js +0 -10
- package/commands/update.js +0 -1
- package/commands/vercel.js +4 -2
- package/commands/visualize.js +0 -5
- package/commands/voice.js +195 -0
- package/commands/watch.js +1 -28
- package/commands/wiki.js +42 -15
- package/commands/wish.js +0 -1
- package/commands/workflow.js +2 -2
- package/commands/worktree.js +88 -28
- package/commands/xp.js +28 -30
- package/commands/youtube.js +0 -2
- package/lib/accept-verify-gate.js +126 -0
- package/lib/activity-stream.js +0 -2
- package/lib/arg-parser.js +41 -0
- package/lib/auto-accept-certified.js +261 -3
- package/lib/autoland.js +66 -3
- package/lib/ax-auto-lane.js +68 -7
- package/lib/bench/context.js +0 -2
- package/lib/bench/report.js +0 -1
- package/lib/bench/runner.js +18 -11
- package/lib/brief-ledger.js +0 -6
- package/lib/business-simulate.js +382 -0
- package/lib/chat-log-scan.js +0 -5
- package/lib/checkout-sync.js +52 -0
- package/lib/claude-boot-block.js +48 -0
- package/lib/cloud-mission.js +0 -6
- package/lib/codex-flight.js +0 -1
- package/lib/conductor-artifacts.js +25 -0
- package/lib/context-gatherer.js +7 -2
- package/lib/deck-compose.js +0 -1
- package/lib/deck-history.js +0 -1
- package/lib/deck-layout.js +0 -5
- package/lib/deck-review.js +0 -7
- package/lib/deck-schema.js +0 -1
- package/lib/default-verifier.js +0 -2
- package/lib/engine-registry.js +157 -28
- package/lib/experiments/daily.js +0 -6
- package/lib/falsifier-probe.js +84 -0
- package/lib/fleet.js +275 -42
- package/lib/functional-owner.js +0 -3
- package/lib/git-spawn.js +15 -0
- package/lib/inspect-fields.js +0 -1
- package/lib/json-file.js +37 -0
- package/lib/known-commands.js +2 -2
- package/lib/learnings.js +0 -2
- package/lib/lesson-preflight.js +146 -0
- package/lib/loop-doctor.js +11 -19
- package/lib/manifest.js +0 -2
- package/lib/member-alive.js +0 -1
- package/lib/member-switches.js +0 -5
- package/lib/mission-artifact.js +0 -1
- package/lib/mission-human-asks.js +28 -0
- package/lib/mission-protected-lane.js +296 -0
- package/lib/mission-room.js +0 -2
- package/lib/mission-runtime-loop.js +0 -1
- package/lib/next-moves.js +0 -18
- package/lib/official-cli-integration.js +47 -6
- package/lib/orb-context.js +14 -4
- package/lib/orb-scorecard.js +0 -1
- package/lib/outbound-send-gate.js +0 -6
- package/lib/pack-capabilities.js +685 -0
- package/lib/permission-grants.js +0 -6
- package/lib/policy-lessons.js +0 -2
- package/lib/pulse.js +68 -15
- package/lib/review-integrity.js +0 -2
- package/lib/router-brain.js +51 -3
- package/lib/runner-command.js +0 -10
- package/lib/runtime-bootstrap.js +0 -1
- package/lib/scorecard.js +0 -1
- package/lib/self-drive.js +45 -14
- package/lib/state-detection.js +0 -6
- package/lib/task-db.js +137 -7
- package/lib/task-decision.js +50 -0
- package/lib/taste-lessons.js +153 -0
- package/lib/team-presence.js +0 -1
- package/lib/tool-result-encode.js +17 -1
- package/lib/voice-gate.js +129 -2
- package/lib/wiki.js +152 -9
- package/lib/wish-audit.js +21 -7
- package/lib/wish-delegate.js +27 -21
- package/lib/wish-stats.js +0 -5
- package/lib/wish-store.js +0 -1
- package/lib/workspace-safety.js +0 -2
- package/lib/zip.js +95 -8
- package/package.json +2 -1
- package/templates/business-starter/persona.md +9 -0
package/commands/bench.js
CHANGED
|
@@ -8,12 +8,10 @@ const {
|
|
|
8
8
|
taskMetadata,
|
|
9
9
|
} = require('../lib/bench/runner');
|
|
10
10
|
const { buildBenchReport, renderBenchReportText } = require('../lib/bench/report');
|
|
11
|
+
const { hasFlag } = require('../lib/arg-parser');
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function readFlag(args, name) {
|
|
13
|
+
// Preserve the existing rule that any inline value wins over a split value.
|
|
14
|
+
function readInlineFirstFlag(args, name) {
|
|
17
15
|
const prefix = `${name}=`;
|
|
18
16
|
const inline = args.find((arg) => String(arg).startsWith(prefix));
|
|
19
17
|
if (inline) return String(inline).slice(prefix.length);
|
|
@@ -58,11 +56,11 @@ async function runCommand(args) {
|
|
|
58
56
|
const asJson = hasFlag(args, '--json');
|
|
59
57
|
try {
|
|
60
58
|
const result = await runBench({
|
|
61
|
-
pack:
|
|
62
|
-
engine:
|
|
59
|
+
pack: readInlineFirstFlag(args, '--pack') || undefined,
|
|
60
|
+
engine: readInlineFirstFlag(args, '--engine') || undefined,
|
|
63
61
|
taskIds: readRepeatedFlag(args, '--task'),
|
|
64
|
-
label:
|
|
65
|
-
experiment:
|
|
62
|
+
label: readInlineFirstFlag(args, '--label'),
|
|
63
|
+
experiment: readInlineFirstFlag(args, '--experiment'),
|
|
66
64
|
updateBaseline: hasFlag(args, '--update-baseline'),
|
|
67
65
|
stateRoot: process.cwd(),
|
|
68
66
|
});
|
|
@@ -87,7 +85,7 @@ async function runCommand(args) {
|
|
|
87
85
|
}
|
|
88
86
|
|
|
89
87
|
function tasksCommand(args) {
|
|
90
|
-
const pack =
|
|
88
|
+
const pack = readInlineFirstFlag(args, '--pack') || undefined;
|
|
91
89
|
const tasks = taskMetadata({ pack });
|
|
92
90
|
if (hasFlag(args, '--json')) {
|
|
93
91
|
console.log(JSON.stringify({
|
|
@@ -121,7 +119,7 @@ function packsCommand(args) {
|
|
|
121
119
|
}
|
|
122
120
|
|
|
123
121
|
function resultsCommand(args) {
|
|
124
|
-
const last = Number(
|
|
122
|
+
const last = Number(readInlineFirstFlag(args, '--last') || 0);
|
|
125
123
|
const results = readResultRecords({ stateRoot: process.cwd(), last });
|
|
126
124
|
if (hasFlag(args, '--json')) {
|
|
127
125
|
console.log(JSON.stringify({
|
|
@@ -143,7 +141,7 @@ function resultsCommand(args) {
|
|
|
143
141
|
}
|
|
144
142
|
|
|
145
143
|
function reportCommand(args) {
|
|
146
|
-
const pack =
|
|
144
|
+
const pack = readInlineFirstFlag(args, '--pack') || undefined;
|
|
147
145
|
const asJson = hasFlag(args, '--json');
|
|
148
146
|
try {
|
|
149
147
|
const report = buildBenchReport({ pack, stateRoot: process.cwd() });
|
package/commands/brain.js
CHANGED
|
@@ -1714,17 +1714,10 @@ function brainCommand(args = process.argv.slice(3)) {
|
|
|
1714
1714
|
module.exports = {
|
|
1715
1715
|
brainCommand,
|
|
1716
1716
|
collectState,
|
|
1717
|
-
prepareBrainState,
|
|
1718
1717
|
renderStatus,
|
|
1719
|
-
renderLedger,
|
|
1720
|
-
renderActivationCard,
|
|
1721
|
-
renderActivationGallery,
|
|
1722
1718
|
recordTaskEpisodeScorecards,
|
|
1723
|
-
recordFeedback,
|
|
1724
|
-
recordApproval,
|
|
1725
1719
|
verifyActivationCard,
|
|
1726
1720
|
verifyActivationGallery,
|
|
1727
|
-
verifyBrain,
|
|
1728
1721
|
parseContributionCard,
|
|
1729
1722
|
escapeRegExp,
|
|
1730
1723
|
countTodoItems,
|
package/commands/brief.js
CHANGED
package/commands/business.js
CHANGED
|
@@ -6,6 +6,12 @@ const { apiRequestJson } = require('../utils/api');
|
|
|
6
6
|
const { syncBusinessCanonical, ensureWorkspaceStateFiles, ensureBusinessRootAgentAdapters } = require('./sync');
|
|
7
7
|
const { ensureContextScaffold, writeWikiStatus, appendWikiLog } = require('../lib/wiki');
|
|
8
8
|
const { writeRuntimeReceipt } = require('../lib/runtime-bootstrap');
|
|
9
|
+
const {
|
|
10
|
+
SIMULATE_USAGE,
|
|
11
|
+
buildSimulationPlan,
|
|
12
|
+
parseSimulationArgs,
|
|
13
|
+
renderDryRun,
|
|
14
|
+
} = require('../lib/business-simulate');
|
|
9
15
|
|
|
10
16
|
function getBusinessConfigPath() {
|
|
11
17
|
const home = require('os').homedir();
|
|
@@ -2022,6 +2028,328 @@ function activityBar(daysSinceActive, width = 10) {
|
|
|
2022
2028
|
return '\u2501'.repeat(filled) + '\u2591'.repeat(width - filled);
|
|
2023
2029
|
}
|
|
2024
2030
|
|
|
2031
|
+
function asRecord(value) {
|
|
2032
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
function firstString(...values) {
|
|
2036
|
+
for (const value of values) {
|
|
2037
|
+
if (typeof value === 'string' && value.trim()) return value.trim();
|
|
2038
|
+
}
|
|
2039
|
+
return '';
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
function firstNumber(...values) {
|
|
2043
|
+
for (const value of values) {
|
|
2044
|
+
const parsed = typeof value === 'number'
|
|
2045
|
+
? value
|
|
2046
|
+
: (typeof value === 'string' && value.trim() ? Number(value) : Number.NaN);
|
|
2047
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
2048
|
+
}
|
|
2049
|
+
return 0;
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
function firstBoolean(...values) {
|
|
2053
|
+
for (const value of values) {
|
|
2054
|
+
if (typeof value === 'boolean') return value;
|
|
2055
|
+
if (value === 1 || value === '1' || value === 'true') return true;
|
|
2056
|
+
if (value === 0 || value === '0' || value === 'false') return false;
|
|
2057
|
+
}
|
|
2058
|
+
return false;
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
function normalizeOrdersPayload(value) {
|
|
2062
|
+
const root = asRecord(value);
|
|
2063
|
+
const body = asRecord(root.data);
|
|
2064
|
+
const source = Object.keys(body).length > 0 ? body : root;
|
|
2065
|
+
const summary = asRecord(source.summary);
|
|
2066
|
+
const rawOrders = Array.isArray(value)
|
|
2067
|
+
? value
|
|
2068
|
+
: (Array.isArray(source.orders) ? source.orders : (Array.isArray(root.orders) ? root.orders : []));
|
|
2069
|
+
const orders = rawOrders.map((rawOrder, index) => {
|
|
2070
|
+
const order = asRecord(rawOrder);
|
|
2071
|
+
const product = asRecord(order.product);
|
|
2072
|
+
const item = asRecord(order.item);
|
|
2073
|
+
const buyer = asRecord(order.buyer);
|
|
2074
|
+
const customer = asRecord(order.customer);
|
|
2075
|
+
const metadata = asRecord(order.metadata);
|
|
2076
|
+
const firstItem = Array.isArray(order.items) ? asRecord(order.items[0]) : {};
|
|
2077
|
+
const status = firstString(order.status, order.payment_status, order.order_type).toLowerCase();
|
|
2078
|
+
const createdAt = firstString(
|
|
2079
|
+
order.created_at,
|
|
2080
|
+
order.createdAt,
|
|
2081
|
+
order.order_date,
|
|
2082
|
+
order.date,
|
|
2083
|
+
order.paid_at,
|
|
2084
|
+
) || null;
|
|
2085
|
+
|
|
2086
|
+
return {
|
|
2087
|
+
id: firstString(order.id, order.order_id, order.reference) || `order-${index + 1}`,
|
|
2088
|
+
reference: firstString(order.order_ref, order.reference, order.order_number, order.id) || `order ${index + 1}`,
|
|
2089
|
+
product: firstString(
|
|
2090
|
+
order.product_name,
|
|
2091
|
+
order.product_title,
|
|
2092
|
+
typeof order.product === 'string' ? order.product : null,
|
|
2093
|
+
product.name,
|
|
2094
|
+
product.title,
|
|
2095
|
+
item.name,
|
|
2096
|
+
firstItem.name,
|
|
2097
|
+
firstItem.product_name,
|
|
2098
|
+
metadata.product_name,
|
|
2099
|
+
) || 'product',
|
|
2100
|
+
quantity: Math.max(1, Math.round(firstNumber(order.quantity, order.qty, firstItem.quantity, 1))),
|
|
2101
|
+
buyer: firstString(
|
|
2102
|
+
order.buyer_name,
|
|
2103
|
+
order.customer_name,
|
|
2104
|
+
buyer.name,
|
|
2105
|
+
customer.name,
|
|
2106
|
+
order.buyer_email,
|
|
2107
|
+
order.customer_email,
|
|
2108
|
+
buyer.email,
|
|
2109
|
+
customer.email,
|
|
2110
|
+
) || 'guest',
|
|
2111
|
+
status: status || 'unknown',
|
|
2112
|
+
isPreorder: firstBoolean(order.is_preorder, order.preorder)
|
|
2113
|
+
|| status.replace(/[_-]/g, '').includes('preorder')
|
|
2114
|
+
|| status === 'pending',
|
|
2115
|
+
amountCents: firstNumber(order.amount_cents, order.price_cents, order.total_cents, firstItem.amount_cents),
|
|
2116
|
+
createdAt,
|
|
2117
|
+
};
|
|
2118
|
+
});
|
|
2119
|
+
|
|
2120
|
+
orders.sort((a, b) => {
|
|
2121
|
+
const aTime = a.createdAt ? Date.parse(a.createdAt) : 0;
|
|
2122
|
+
const bTime = b.createdAt ? Date.parse(b.createdAt) : 0;
|
|
2123
|
+
return (Number.isFinite(bTime) ? bTime : 0) - (Number.isFinite(aTime) ? aTime : 0);
|
|
2124
|
+
});
|
|
2125
|
+
|
|
2126
|
+
return {
|
|
2127
|
+
orders,
|
|
2128
|
+
revenueCents: firstNumber(summary.revenue_cents, source.revenue_cents, root.revenue_cents),
|
|
2129
|
+
paidOrders: Math.max(0, Math.round(firstNumber(summary.paid_orders, source.paid_orders, root.paid_orders))),
|
|
2130
|
+
pendingRevenueCents: firstNumber(
|
|
2131
|
+
summary.pending_revenue_cents,
|
|
2132
|
+
source.pending_revenue_cents,
|
|
2133
|
+
root.pending_revenue_cents,
|
|
2134
|
+
),
|
|
2135
|
+
};
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
function readStorefront(business) {
|
|
2139
|
+
const config = asRecord(asRecord(business).config);
|
|
2140
|
+
const storefront = asRecord(config.storefront);
|
|
2141
|
+
return {
|
|
2142
|
+
enabled: storefront.enabled === true,
|
|
2143
|
+
products: Array.isArray(storefront.products) ? storefront.products.filter(product => product && typeof product === 'object') : [],
|
|
2144
|
+
};
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
function readWalletNet(business) {
|
|
2148
|
+
const config = asRecord(asRecord(business).config);
|
|
2149
|
+
for (const key of ['wallet_balance', 'credits_balance', 'credits', 'wallet_credits']) {
|
|
2150
|
+
const value = config[key];
|
|
2151
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value;
|
|
2152
|
+
}
|
|
2153
|
+
return null;
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2156
|
+
function formatWalletNet(value) {
|
|
2157
|
+
if (value === null) return 'not available';
|
|
2158
|
+
return `$${value.toLocaleString('en-US', { maximumFractionDigits: 2 })}`;
|
|
2159
|
+
}
|
|
2160
|
+
|
|
2161
|
+
function formatCents(value, currency = 'usd') {
|
|
2162
|
+
const amount = firstNumber(value) / 100;
|
|
2163
|
+
const code = firstString(currency).toUpperCase() || 'USD';
|
|
2164
|
+
const formatted = amount.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
2165
|
+
return code === 'USD' ? `$${formatted}` : `${code} ${formatted}`;
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
function businessOperationError(message) {
|
|
2169
|
+
console.error(message);
|
|
2170
|
+
process.exitCode = 1;
|
|
2171
|
+
return null;
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
async function resolveBusinessOperation(slug, usage) {
|
|
2175
|
+
const requestedSlug = detectBusinessSlug(slug);
|
|
2176
|
+
if (!requestedSlug) return businessOperationError(`No business specified. Usage: ${usage}`);
|
|
2177
|
+
|
|
2178
|
+
const creds = loadCredentials();
|
|
2179
|
+
if (!creds || !creds.token) return businessOperationError('Not logged in. Run: atris login');
|
|
2180
|
+
|
|
2181
|
+
const resolved = await resolveSlug(requestedSlug, creds);
|
|
2182
|
+
if (!resolved) return businessOperationError(`Business "${requestedSlug}" not found.`);
|
|
2183
|
+
return { requestedSlug, resolved, token: creds.token };
|
|
2184
|
+
}
|
|
2185
|
+
|
|
2186
|
+
async function fetchBusinessDashboard(context) {
|
|
2187
|
+
const result = await apiRequestJson(`/business/${context.resolved.business_id}/dashboard`, {
|
|
2188
|
+
method: 'GET',
|
|
2189
|
+
token: context.token,
|
|
2190
|
+
timeoutMs: 120000,
|
|
2191
|
+
});
|
|
2192
|
+
if (!result.ok) {
|
|
2193
|
+
const detail = result.errorMessage || result.error || `HTTP ${result.status}`;
|
|
2194
|
+
return businessOperationError(`Could not load business room: ${detail}`);
|
|
2195
|
+
}
|
|
2196
|
+
return result.data || {};
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2199
|
+
async function fetchBusinessOrders(context, limit = 50) {
|
|
2200
|
+
return apiRequestJson(`/storefront/${context.resolved.business_id}/orders?limit=${limit}`, {
|
|
2201
|
+
method: 'GET',
|
|
2202
|
+
token: context.token,
|
|
2203
|
+
timeoutMs: 120000,
|
|
2204
|
+
});
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2207
|
+
function renderOrderLine(order) {
|
|
2208
|
+
const kind = order.isPreorder ? ', preorder' : '';
|
|
2209
|
+
const when = order.createdAt ? relativeTime(order.createdAt) : 'date unavailable';
|
|
2210
|
+
return ` ${order.reference}: ${order.product} x${order.quantity}, ${order.buyer}, ${when}${kind}`;
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
async function businessRoom(slug) {
|
|
2214
|
+
const context = await resolveBusinessOperation(slug, 'atris business room <slug>');
|
|
2215
|
+
if (!context) return;
|
|
2216
|
+
|
|
2217
|
+
const [dashboard, ordersResult] = await Promise.all([
|
|
2218
|
+
fetchBusinessDashboard(context),
|
|
2219
|
+
fetchBusinessOrders(context, 5),
|
|
2220
|
+
]);
|
|
2221
|
+
if (!dashboard) return;
|
|
2222
|
+
|
|
2223
|
+
const business = asRecord(dashboard.business);
|
|
2224
|
+
const roster = asRecord(dashboard.roster);
|
|
2225
|
+
const members = Array.isArray(roster.members)
|
|
2226
|
+
? roster.members
|
|
2227
|
+
: (Array.isArray(business.members) ? business.members : []);
|
|
2228
|
+
const storefront = readStorefront(business);
|
|
2229
|
+
const orders = ordersResult.ok ? normalizeOrdersPayload(ordersResult.data).orders.slice(0, 5) : [];
|
|
2230
|
+
const name = business.name || context.resolved.name || context.requestedSlug;
|
|
2231
|
+
const appCount = Number.isFinite(business.app_count)
|
|
2232
|
+
? business.app_count
|
|
2233
|
+
: (Array.isArray(business.apps) ? business.apps.length : 0);
|
|
2234
|
+
|
|
2235
|
+
console.log('');
|
|
2236
|
+
console.log(`business room: ${name}`);
|
|
2237
|
+
console.log(`wallet/net: ${formatWalletNet(readWalletNet(business))}`);
|
|
2238
|
+
console.log(`members: ${members.length}`);
|
|
2239
|
+
for (const member of members) {
|
|
2240
|
+
const agent = asRecord(member.atris);
|
|
2241
|
+
const memberName = firstString(member.display_name, agent.agent_name, member.name, member.email) || 'unknown';
|
|
2242
|
+
console.log(` ${memberName} (${member.role || 'member'})`);
|
|
2243
|
+
}
|
|
2244
|
+
console.log(`apps: ${appCount}`);
|
|
2245
|
+
console.log(`store: ${storefront.enabled ? 'enabled' : 'disabled'}, ${storefront.products.length} products`);
|
|
2246
|
+
console.log('recent orders:');
|
|
2247
|
+
if (!ordersResult.ok) {
|
|
2248
|
+
const detail = ordersResult.errorMessage || ordersResult.error || `HTTP ${ordersResult.status}`;
|
|
2249
|
+
console.log(` unavailable: ${detail}`);
|
|
2250
|
+
process.exitCode = 1;
|
|
2251
|
+
} else if (orders.length === 0) {
|
|
2252
|
+
console.log(' none');
|
|
2253
|
+
} else {
|
|
2254
|
+
orders.forEach(order => console.log(renderOrderLine(order)));
|
|
2255
|
+
}
|
|
2256
|
+
console.log('');
|
|
2257
|
+
}
|
|
2258
|
+
|
|
2259
|
+
async function businessProducts(slug) {
|
|
2260
|
+
const context = await resolveBusinessOperation(slug, 'atris business products <slug>');
|
|
2261
|
+
if (!context) return;
|
|
2262
|
+
const dashboard = await fetchBusinessDashboard(context);
|
|
2263
|
+
if (!dashboard) return;
|
|
2264
|
+
|
|
2265
|
+
const business = asRecord(dashboard.business);
|
|
2266
|
+
const storefront = readStorefront(business);
|
|
2267
|
+
const name = business.name || context.resolved.name || context.requestedSlug;
|
|
2268
|
+
console.log('');
|
|
2269
|
+
console.log(`products: ${name} (${storefront.products.length})`);
|
|
2270
|
+
if (storefront.products.length === 0) {
|
|
2271
|
+
console.log(' none');
|
|
2272
|
+
} else {
|
|
2273
|
+
for (const product of storefront.products) {
|
|
2274
|
+
const productName = firstString(product.name) || 'unnamed product';
|
|
2275
|
+
const productId = firstString(product.id) || 'no id';
|
|
2276
|
+
console.log(` ${productName} (${productId}): ${formatCents(product.price_cents, product.currency)}`);
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
console.log('');
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
async function businessOrders(slug) {
|
|
2283
|
+
const context = await resolveBusinessOperation(slug, 'atris business orders <slug>');
|
|
2284
|
+
if (!context) return;
|
|
2285
|
+
const result = await fetchBusinessOrders(context, 50);
|
|
2286
|
+
if (!result.ok) {
|
|
2287
|
+
const detail = result.errorMessage || result.error || `HTTP ${result.status}`;
|
|
2288
|
+
businessOperationError(`Could not load orders: ${detail}`);
|
|
2289
|
+
return;
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2292
|
+
const data = normalizeOrdersPayload(result.data);
|
|
2293
|
+
const name = context.resolved.name || context.requestedSlug;
|
|
2294
|
+
console.log('');
|
|
2295
|
+
console.log(`orders: ${name} (${data.orders.length})`);
|
|
2296
|
+
console.log(`revenue: ${formatCents(data.revenueCents)}`);
|
|
2297
|
+
console.log(`paid orders: ${data.paidOrders}`);
|
|
2298
|
+
console.log(`pending revenue: ${formatCents(data.pendingRevenueCents)}`);
|
|
2299
|
+
if (data.orders.length === 0) {
|
|
2300
|
+
console.log(' none');
|
|
2301
|
+
} else {
|
|
2302
|
+
data.orders.forEach(order => console.log(renderOrderLine(order)));
|
|
2303
|
+
}
|
|
2304
|
+
console.log('');
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2307
|
+
function parseBusinessStoreArgs(args = []) {
|
|
2308
|
+
const actions = new Set(['status', 'on', 'enable', 'toggle', 'off', 'disable']);
|
|
2309
|
+
if (actions.has(args[0])) return { action: args[0], slug: args[1] };
|
|
2310
|
+
if (actions.has(args[1])) return { action: args[1], slug: args[0] };
|
|
2311
|
+
return { action: 'status', slug: args[0] };
|
|
2312
|
+
}
|
|
2313
|
+
|
|
2314
|
+
async function businessStore(args = []) {
|
|
2315
|
+
const { action, slug } = parseBusinessStoreArgs(args);
|
|
2316
|
+
if (action === 'off' || action === 'disable') {
|
|
2317
|
+
businessOperationError('The production store API does not support disabling stores yet.');
|
|
2318
|
+
return;
|
|
2319
|
+
}
|
|
2320
|
+
|
|
2321
|
+
const context = await resolveBusinessOperation(slug, 'atris business store <on|status> [slug]');
|
|
2322
|
+
if (!context) return;
|
|
2323
|
+
const dashboard = await fetchBusinessDashboard(context);
|
|
2324
|
+
if (!dashboard) return;
|
|
2325
|
+
|
|
2326
|
+
const business = asRecord(dashboard.business);
|
|
2327
|
+
const storefront = readStorefront(business);
|
|
2328
|
+
const name = business.name || context.resolved.name || context.requestedSlug;
|
|
2329
|
+
if (action === 'status') {
|
|
2330
|
+
console.log(`store: ${storefront.enabled ? 'enabled' : 'disabled'} for ${name}, ${storefront.products.length} products`);
|
|
2331
|
+
return;
|
|
2332
|
+
}
|
|
2333
|
+
if (storefront.enabled) {
|
|
2334
|
+
console.log(`store: already enabled for ${name}, ${storefront.products.length} products`);
|
|
2335
|
+
return;
|
|
2336
|
+
}
|
|
2337
|
+
|
|
2338
|
+
const result = await apiRequestJson(`/storefront/${context.resolved.business_id}/products`, {
|
|
2339
|
+
method: 'PUT',
|
|
2340
|
+
token: context.token,
|
|
2341
|
+
body: { products: storefront.products },
|
|
2342
|
+
timeoutMs: 120000,
|
|
2343
|
+
});
|
|
2344
|
+
if (!result.ok) {
|
|
2345
|
+
const detail = result.errorMessage || result.error || `HTTP ${result.status}`;
|
|
2346
|
+
businessOperationError(`Could not enable store: ${detail}`);
|
|
2347
|
+
return;
|
|
2348
|
+
}
|
|
2349
|
+
const enabledProducts = Array.isArray(result.data?.products) ? result.data.products.length : storefront.products.length;
|
|
2350
|
+
console.log(`store: enabled for ${name}, ${enabledProducts} products`);
|
|
2351
|
+
}
|
|
2352
|
+
|
|
2025
2353
|
// ---------------------------------------------------------------------------
|
|
2026
2354
|
// atris business health <slug>
|
|
2027
2355
|
// ---------------------------------------------------------------------------
|
|
@@ -2386,6 +2714,7 @@ async function createBusinessInternal(name, flags = [], mode = 'auto') {
|
|
|
2386
2714
|
options.here ||
|
|
2387
2715
|
Boolean(options.root)
|
|
2388
2716
|
);
|
|
2717
|
+
let workspaceRoot = null;
|
|
2389
2718
|
|
|
2390
2719
|
// Scaffold legacy local directory if in an atris project
|
|
2391
2720
|
const atrisDir = !shouldCreateCanonicalWorkspace ? findAtrisDir() : null;
|
|
@@ -2405,7 +2734,7 @@ async function createBusinessInternal(name, flags = [], mode = 'auto') {
|
|
|
2405
2734
|
console.log(` Local scaffold: ${bizDir}/`);
|
|
2406
2735
|
}
|
|
2407
2736
|
} else if (shouldCreateCanonicalWorkspace) {
|
|
2408
|
-
|
|
2737
|
+
workspaceRoot = resolveWorkspaceRoot(biz.slug, options);
|
|
2409
2738
|
const scaffold = createCanonicalBusinessWorkspace(workspaceRoot, {
|
|
2410
2739
|
business_id: biz.id,
|
|
2411
2740
|
workspace_id: biz.workspace_id,
|
|
@@ -2446,10 +2775,10 @@ async function createBusinessInternal(name, flags = [], mode = 'auto') {
|
|
|
2446
2775
|
console.log(` Agent: ${biz.agent_id || '(none)'}`);
|
|
2447
2776
|
console.log(` Dashboard: https://atris.ai/dashboard/gm/${biz.id}`);
|
|
2448
2777
|
if (shouldCreateCanonicalWorkspace) {
|
|
2449
|
-
const workspaceRoot = resolveWorkspaceRoot(biz.slug, options);
|
|
2450
2778
|
console.log(renderBusinessCreatedNextSteps(biz, workspaceRoot));
|
|
2451
2779
|
}
|
|
2452
2780
|
console.log('');
|
|
2781
|
+
return { business: biz, workspaceRoot };
|
|
2453
2782
|
}
|
|
2454
2783
|
|
|
2455
2784
|
async function createBusiness(name, ...flags) {
|
|
@@ -2875,6 +3204,96 @@ function findAtrisDir() {
|
|
|
2875
3204
|
return null;
|
|
2876
3205
|
}
|
|
2877
3206
|
|
|
3207
|
+
function printBusinessSimulateHelp() {
|
|
3208
|
+
console.log(SIMULATE_USAGE);
|
|
3209
|
+
console.log('');
|
|
3210
|
+
console.log('Creates a business workspace, four simulation members, their missions, and atris/ENDGAME.md.');
|
|
3211
|
+
console.log('Use --dry-run to preview every simulation file without cloud calls or writes.');
|
|
3212
|
+
}
|
|
3213
|
+
|
|
3214
|
+
async function simulateBusiness(args = [], dependencies = {}) {
|
|
3215
|
+
const options = parseSimulationArgs(args);
|
|
3216
|
+
const createdAt = new Date().toISOString();
|
|
3217
|
+
const preview = buildSimulationPlan({
|
|
3218
|
+
idea: options.idea,
|
|
3219
|
+
businessName: options.businessName,
|
|
3220
|
+
roleNames: options.roleNames,
|
|
3221
|
+
createdAt,
|
|
3222
|
+
});
|
|
3223
|
+
|
|
3224
|
+
if (options.dryRun) {
|
|
3225
|
+
console.log(renderDryRun(preview));
|
|
3226
|
+
return preview;
|
|
3227
|
+
}
|
|
3228
|
+
|
|
3229
|
+
const init = dependencies.initBusinessWorkspace || initBusinessWorkspace;
|
|
3230
|
+
const runMemberCommand = dependencies.memberCommand || require('./member').memberCommand;
|
|
3231
|
+
const initialized = await init(options.businessName);
|
|
3232
|
+
const business = initialized?.business || {};
|
|
3233
|
+
const workspaceRoot = initialized?.workspaceRoot
|
|
3234
|
+
|| resolveWorkspaceRoot(business.slug || options.businessSlug, {});
|
|
3235
|
+
const plan = buildSimulationPlan({
|
|
3236
|
+
idea: options.idea,
|
|
3237
|
+
businessName: business.name || options.businessName,
|
|
3238
|
+
businessSlug: business.slug || options.businessSlug,
|
|
3239
|
+
roleNames: options.roleNames,
|
|
3240
|
+
createdAt,
|
|
3241
|
+
workspacePath: workspaceRoot,
|
|
3242
|
+
});
|
|
3243
|
+
|
|
3244
|
+
const businessJson = path.join(workspaceRoot, '.atris', 'business.json');
|
|
3245
|
+
if (!fs.existsSync(businessJson)) {
|
|
3246
|
+
throw new Error(`Business init did not create the expected workspace: ${workspaceRoot}`);
|
|
3247
|
+
}
|
|
3248
|
+
|
|
3249
|
+
const originalCwd = process.cwd();
|
|
3250
|
+
try {
|
|
3251
|
+
process.chdir(workspaceRoot);
|
|
3252
|
+
|
|
3253
|
+
const endgame = plan.files.find((file) => file.kind === 'endgame');
|
|
3254
|
+
fs.writeFileSync(path.join(workspaceRoot, endgame.path), endgame.content, 'utf8');
|
|
3255
|
+
|
|
3256
|
+
for (const role of plan.roles) {
|
|
3257
|
+
const memberDir = path.join(workspaceRoot, 'atris', 'team', role.name);
|
|
3258
|
+
const memberFile = path.join(memberDir, 'MEMBER.md');
|
|
3259
|
+
if (!fs.existsSync(memberFile)) {
|
|
3260
|
+
await runMemberCommand(
|
|
3261
|
+
'create',
|
|
3262
|
+
role.name,
|
|
3263
|
+
`--role=${role.title}`,
|
|
3264
|
+
`--description=${role.description}`,
|
|
3265
|
+
);
|
|
3266
|
+
} else {
|
|
3267
|
+
console.log(`Using existing team/${role.name}/ scaffold from business init.`);
|
|
3268
|
+
}
|
|
3269
|
+
|
|
3270
|
+
for (const directory of ['skills', 'tools', 'context', 'logs']) {
|
|
3271
|
+
fs.mkdirSync(path.join(memberDir, directory), { recursive: true });
|
|
3272
|
+
}
|
|
3273
|
+
|
|
3274
|
+
const roleFiles = plan.files.filter((file) => file.role?.name === role.name);
|
|
3275
|
+
for (const file of roleFiles) {
|
|
3276
|
+
fs.writeFileSync(path.join(workspaceRoot, file.path), file.content, 'utf8');
|
|
3277
|
+
}
|
|
3278
|
+
|
|
3279
|
+
await runMemberCommand('push', role.name);
|
|
3280
|
+
}
|
|
3281
|
+
} finally {
|
|
3282
|
+
process.chdir(originalCwd);
|
|
3283
|
+
}
|
|
3284
|
+
|
|
3285
|
+
console.log('');
|
|
3286
|
+
console.log('business simulation ready');
|
|
3287
|
+
console.log(`workspace: ${workspaceRoot}`);
|
|
3288
|
+
console.log('roster:');
|
|
3289
|
+
for (const role of plan.roles) {
|
|
3290
|
+
console.log(` - ${role.name}: ${role.role}`);
|
|
3291
|
+
}
|
|
3292
|
+
console.log('next: open an agent session in the workspace and run the loop against atris/ENDGAME.md');
|
|
3293
|
+
console.log('');
|
|
3294
|
+
return plan;
|
|
3295
|
+
}
|
|
3296
|
+
|
|
2878
3297
|
|
|
2879
3298
|
async function quickstart() {
|
|
2880
3299
|
console.log(`
|
|
@@ -2945,8 +3364,13 @@ function printBusinessHelp() {
|
|
|
2945
3364
|
console.log(' init <name> RECOMMENDED: create a business environment (cloud + local)');
|
|
2946
3365
|
console.log(' workspace <name> Alias for init');
|
|
2947
3366
|
console.log(' create <name> Cloud-only business record; add --workspace to also scaffold local');
|
|
3367
|
+
console.log(' simulate <idea> Create a business, four-role team, missions, and endgame loop');
|
|
2948
3368
|
console.log(' add <slug> Register an existing cloud business');
|
|
2949
3369
|
console.log(' list Show registered businesses');
|
|
3370
|
+
console.log(' room [slug] Show wallet, members, apps, store, and recent orders');
|
|
3371
|
+
console.log(' products [slug] List store products');
|
|
3372
|
+
console.log(' orders [slug] List store orders');
|
|
3373
|
+
console.log(' store on [slug] Enable the store with its current catalog');
|
|
2950
3374
|
console.log(' team [slug] Show members, roles, and admin access');
|
|
2951
3375
|
console.log(' status <slug> Quick status check');
|
|
2952
3376
|
console.log(' health [slug] Full health dashboard');
|
|
@@ -2973,6 +3397,10 @@ async function businessCommand(subcommand, ...args) {
|
|
|
2973
3397
|
printBusinessHelp();
|
|
2974
3398
|
return;
|
|
2975
3399
|
}
|
|
3400
|
+
if (subcommand === 'simulate' && args.some(isHelpToken)) {
|
|
3401
|
+
printBusinessSimulateHelp();
|
|
3402
|
+
return;
|
|
3403
|
+
}
|
|
2976
3404
|
const nameTakingSubcommands = new Set(['create', 'new', 'init', 'workspace']);
|
|
2977
3405
|
if (nameTakingSubcommands.has(subcommand) && args.some(isHelpToken)) {
|
|
2978
3406
|
printBusinessHelp();
|
|
@@ -2995,6 +3423,9 @@ async function businessCommand(subcommand, ...args) {
|
|
|
2995
3423
|
case 'workspace':
|
|
2996
3424
|
await initBusinessWorkspace(args[0], ...args.slice(1));
|
|
2997
3425
|
break;
|
|
3426
|
+
case 'simulate':
|
|
3427
|
+
await simulateBusiness(args);
|
|
3428
|
+
break;
|
|
2998
3429
|
case 'list':
|
|
2999
3430
|
case 'ls': {
|
|
3000
3431
|
const opts = {};
|
|
@@ -3017,6 +3448,21 @@ async function businessCommand(subcommand, ...args) {
|
|
|
3017
3448
|
case 'health':
|
|
3018
3449
|
await businessHealth(args[0]);
|
|
3019
3450
|
break;
|
|
3451
|
+
case 'room':
|
|
3452
|
+
await businessRoom(args[0]);
|
|
3453
|
+
break;
|
|
3454
|
+
case 'products':
|
|
3455
|
+
case 'product':
|
|
3456
|
+
await businessProducts(args[0]);
|
|
3457
|
+
break;
|
|
3458
|
+
case 'orders':
|
|
3459
|
+
case 'order':
|
|
3460
|
+
await businessOrders(args[0]);
|
|
3461
|
+
break;
|
|
3462
|
+
case 'store':
|
|
3463
|
+
case 'storefront':
|
|
3464
|
+
await businessStore(args);
|
|
3465
|
+
break;
|
|
3020
3466
|
case 'team':
|
|
3021
3467
|
case 'members':
|
|
3022
3468
|
case 'roster':
|
|
@@ -3072,26 +3518,20 @@ async function businessCommand(subcommand, ...args) {
|
|
|
3072
3518
|
|
|
3073
3519
|
module.exports = {
|
|
3074
3520
|
businessCommand,
|
|
3075
|
-
businessHealth,
|
|
3076
|
-
businessAudit,
|
|
3077
|
-
businessDoctor,
|
|
3078
|
-
businessTeam,
|
|
3079
3521
|
loadBusinesses,
|
|
3080
3522
|
saveBusinesses,
|
|
3081
|
-
getBusinessConfigPath,
|
|
3082
3523
|
businessMatchesSlug,
|
|
3083
3524
|
isAccidentalHelpBusiness,
|
|
3084
3525
|
validateBusinessCreateName,
|
|
3085
3526
|
analyzeBusinessDoctor,
|
|
3086
|
-
readBusinessFolderBindings,
|
|
3087
3527
|
createCanonicalBusinessWorkspace,
|
|
3088
|
-
initBusinessWorkspace,
|
|
3089
3528
|
onboardBusiness,
|
|
3090
|
-
startBusinessWorkspace,
|
|
3091
3529
|
shareBusinessWorkspace,
|
|
3092
3530
|
collectBusinessShareState,
|
|
3093
3531
|
renderBusinessCreatedNextSteps,
|
|
3094
|
-
renderBusinessShareHandoff,
|
|
3095
|
-
renderBusinessStartCard,
|
|
3096
3532
|
recordBusinessRun,
|
|
3533
|
+
normalizeOrdersPayload,
|
|
3534
|
+
parseBusinessStoreArgs,
|
|
3535
|
+
readStorefront,
|
|
3536
|
+
readWalletNet,
|
|
3097
3537
|
};
|
package/commands/chat-scan.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const { hasFlag } = require('../lib/arg-parser');
|
|
3
4
|
const { scanChatLogs, writeLatestScan } = require('../lib/chat-log-scan');
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function readFlag(args, name, fallback) {
|
|
6
|
+
// Preserve the existing rule that the next token is a value, even if it is a flag.
|
|
7
|
+
function readFollowingFlag(args, name, fallback) {
|
|
10
8
|
const i = args.indexOf(name);
|
|
11
9
|
if (i === -1 || i === args.length - 1) return fallback;
|
|
12
10
|
return args[i + 1];
|
|
@@ -79,8 +77,8 @@ Options:
|
|
|
79
77
|
|
|
80
78
|
const report = scanChatLogs({
|
|
81
79
|
cwd: root,
|
|
82
|
-
hours:
|
|
83
|
-
limit:
|
|
80
|
+
hours: readFollowingFlag(args, '--hours', 720),
|
|
81
|
+
limit: readFollowingFlag(args, '--limit', 12),
|
|
84
82
|
});
|
|
85
83
|
|
|
86
84
|
let latestPath = null;
|