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/lib/wish-delegate.js
CHANGED
|
@@ -726,7 +726,7 @@ function reviewWish(positionals, root = process.cwd(), options = {}) {
|
|
|
726
726
|
review_score: score.value === null ? reviewWordScore(reviewText) : score.value,
|
|
727
727
|
reviewed_by: actorName(),
|
|
728
728
|
});
|
|
729
|
-
console.log(`Review saved for ${quoteText(target.wish.text || target.wish.id)}. It
|
|
729
|
+
console.log(`Review saved for ${quoteText(target.wish.text || target.wish.id)}. It shapes future runs once distilled into lessons.`);
|
|
730
730
|
return 0;
|
|
731
731
|
}
|
|
732
732
|
|
|
@@ -919,9 +919,13 @@ function startWishDelegation(wish, audit, root, options = {}) {
|
|
|
919
919
|
const reused = missionPayload && missionPayload.action === 'mission_reused';
|
|
920
920
|
// A delegated wish must have a live worker, not just a filed mission. Start
|
|
921
921
|
// the detached driver for any runner that can work headlessly; runners that
|
|
922
|
-
// need a live session keep an honest not-started marker instead.
|
|
922
|
+
// need a live session keep an honest not-started marker instead. A one-lap
|
|
923
|
+
// intake is the exception: the calling lap dispatches in-process through the
|
|
924
|
+
// sealed review sandbox, so a detached driver would race it with a second,
|
|
925
|
+
// ungated dispatch of the same ask.
|
|
923
926
|
let driver = null;
|
|
924
|
-
|
|
927
|
+
const lapOwnsDispatch = options.oneLap === true;
|
|
928
|
+
if (mission && !lapOwnsDispatch && !missionRunnerNeedsLiveSession(mission.runner) && process.env.ATRIS_WISH_NO_DRIVER !== '1') {
|
|
925
929
|
driver = spawnMissionDriver(mission, root);
|
|
926
930
|
}
|
|
927
931
|
const workerStarted = Boolean(driver && driver.ok && (driver.pid || driver.already_running));
|
|
@@ -940,9 +944,11 @@ function startWishDelegation(wish, audit, root, options = {}) {
|
|
|
940
944
|
worker_started: workerStarted,
|
|
941
945
|
...(driver && driver.pid ? { driver_pid: driver.pid } : {}),
|
|
942
946
|
...(mission && !workerStarted ? {
|
|
943
|
-
worker_note:
|
|
944
|
-
?
|
|
945
|
-
:
|
|
947
|
+
worker_note: lapOwnsDispatch
|
|
948
|
+
? 'the one-lap dispatches this in-process'
|
|
949
|
+
: missionRunnerNeedsLiveSession(mission.runner)
|
|
950
|
+
? `waiting for a live ${mission.runner || 'session'} to pick this up`
|
|
951
|
+
: `worker did not start; run: atris mission run ${mission.id}`,
|
|
946
952
|
} : {}),
|
|
947
953
|
engine: reused ? (mission?.runner || engine) : engine,
|
|
948
954
|
validator: audit.validator.id,
|
|
@@ -1422,7 +1428,12 @@ function dispatchWishHeadlessly(wish, root, reason) {
|
|
|
1422
1428
|
questions: audit.questions,
|
|
1423
1429
|
};
|
|
1424
1430
|
}
|
|
1425
|
-
|
|
1431
|
+
// Preserve one-lap ownership through sweep/headless grant: without this,
|
|
1432
|
+
// a later atris wish sweep would spawn the detached mission driver and race
|
|
1433
|
+
// the lap's sealed in-process dispatch (CLI-1170).
|
|
1434
|
+
const { record } = appendDelegatedWishRecord(wish, audit, root, {
|
|
1435
|
+
oneLap: wish.one_lap === true,
|
|
1436
|
+
});
|
|
1426
1437
|
return {
|
|
1427
1438
|
id: wish.id,
|
|
1428
1439
|
status: 'delegated',
|
|
@@ -1531,6 +1542,9 @@ function runCapturedWish(text, root = process.cwd(), options = {}) {
|
|
|
1531
1542
|
status: 'captured',
|
|
1532
1543
|
};
|
|
1533
1544
|
if (options.parentId) wish.parent_id = String(options.parentId);
|
|
1545
|
+
// One-lap provenance lives on the record so a later `wish answer` also
|
|
1546
|
+
// skips the detached driver: the lap owns dispatch in-process (80de4ae1).
|
|
1547
|
+
if (options.singleTask === true) wish.one_lap = true;
|
|
1534
1548
|
if (engineOverride) wish.requested_engine = engineOverride;
|
|
1535
1549
|
if (options.metric && options.metric.ok) wish.metric = options.metric.expression;
|
|
1536
1550
|
captureWishToJournal(text, root);
|
|
@@ -1539,7 +1553,10 @@ function runCapturedWish(text, root = process.cwd(), options = {}) {
|
|
|
1539
1553
|
const taskText = wishBodyText(text);
|
|
1540
1554
|
const verifyPlan = options.verifyPlan || deriveVerifyPlan(text);
|
|
1541
1555
|
const decompositionVerifyPlan = options.verifyPlan || (verifyPlan.status === 'explicit' ? verifyPlan : null);
|
|
1542
|
-
|
|
1556
|
+
// A one-lap intake owns dispatch and validation policy in-process, so its
|
|
1557
|
+
// route must stay deterministic across machines: never interview about the
|
|
1558
|
+
// reviewer just because no validator binary is installed here.
|
|
1559
|
+
const audit = auditWish(taskText, root, { engineOverride, assumeValidator: options.singleTask === true });
|
|
1543
1560
|
if (builderMode) return builderWish(wish, audit, root, asJson);
|
|
1544
1561
|
const parts = options.singleTask ? null : analyzeWishParts(text, root);
|
|
1545
1562
|
if (parts && noMission) return captureOnlyWish(wish, null, root, asJson);
|
|
@@ -1552,6 +1569,7 @@ function runCapturedWish(text, root = process.cwd(), options = {}) {
|
|
|
1552
1569
|
return delegateWish(wish, audit, root, asJson, {
|
|
1553
1570
|
taskText,
|
|
1554
1571
|
recordText: wish.text,
|
|
1572
|
+
oneLap: options.singleTask === true,
|
|
1555
1573
|
...(options.metric ? { metric: options.metric } : {}),
|
|
1556
1574
|
verifyPlan,
|
|
1557
1575
|
userVerifyProvided: options.userVerifyProvided === true || verifyPlan.status === 'explicit',
|
|
@@ -1622,7 +1640,7 @@ function applyAnswer(wish, answer, root, options = {}) {
|
|
|
1622
1640
|
const audit = bestGuessAfterRepeatedQuestion(answeredWish, audited, root);
|
|
1623
1641
|
if (!audit.ok) return askForInput(answeredWish, audit, root, asJson);
|
|
1624
1642
|
if (noMission) return captureOnlyWish(answeredWish, audit, root, asJson);
|
|
1625
|
-
return delegateWish(answeredWish, audit, root, asJson, {});
|
|
1643
|
+
return delegateWish(answeredWish, audit, root, asJson, { oneLap: wish.one_lap === true });
|
|
1626
1644
|
}
|
|
1627
1645
|
|
|
1628
1646
|
function sameWaitingPart(left, right) {
|
|
@@ -1811,25 +1829,13 @@ function grantWish(positionals, root = process.cwd(), options = {}) {
|
|
|
1811
1829
|
module.exports = {
|
|
1812
1830
|
REVIEW_WORD_SCORES,
|
|
1813
1831
|
answerWish,
|
|
1814
|
-
appendDelegatedWishRecord,
|
|
1815
|
-
appendNeedsInputRecord,
|
|
1816
|
-
askForInput,
|
|
1817
|
-
captureOnlyWish,
|
|
1818
1832
|
captureWishToJournal,
|
|
1819
|
-
delegateWish,
|
|
1820
|
-
dispatchWishHeadlessly,
|
|
1821
|
-
fulfillLandedWishes,
|
|
1822
1833
|
grantWish,
|
|
1823
|
-
metricVerifierCommand,
|
|
1824
|
-
listedWishes,
|
|
1825
|
-
openWishes,
|
|
1826
1834
|
parseMetricExpression,
|
|
1827
1835
|
printBoard,
|
|
1828
1836
|
printList,
|
|
1829
1837
|
printReviewNudges,
|
|
1830
1838
|
printRewards,
|
|
1831
|
-
reviewNudgeWishes,
|
|
1832
|
-
reviewWordScore,
|
|
1833
1839
|
reviewWish,
|
|
1834
1840
|
runAgainWish,
|
|
1835
1841
|
runCapturedWish,
|
package/lib/wish-stats.js
CHANGED
package/lib/wish-store.js
CHANGED
package/lib/workspace-safety.js
CHANGED
package/lib/zip.js
CHANGED
|
@@ -11,6 +11,13 @@ const UTF8_FLAG = 0x0800;
|
|
|
11
11
|
const DEFLATE = 8;
|
|
12
12
|
const STORE = 0;
|
|
13
13
|
|
|
14
|
+
const ZIP_LIMITS = Object.freeze({
|
|
15
|
+
maxZipBytes: 5 * 1024 * 1024,
|
|
16
|
+
maxUnpackedBytes: 20 * 1024 * 1024,
|
|
17
|
+
maxEntryBytes: 20 * 1024 * 1024,
|
|
18
|
+
maxEntries: 500,
|
|
19
|
+
});
|
|
20
|
+
|
|
14
21
|
let crcTable = null;
|
|
15
22
|
|
|
16
23
|
function getCrcTable() {
|
|
@@ -155,24 +162,56 @@ function assertReadable(buffer, offset, length, label) {
|
|
|
155
162
|
}
|
|
156
163
|
}
|
|
157
164
|
|
|
158
|
-
function
|
|
165
|
+
function readLimits(options = {}) {
|
|
166
|
+
return {
|
|
167
|
+
maxZipBytes: options.maxZipBytes ?? ZIP_LIMITS.maxZipBytes,
|
|
168
|
+
maxUnpackedBytes: options.maxUnpackedBytes ?? ZIP_LIMITS.maxUnpackedBytes,
|
|
169
|
+
maxEntryBytes: options.maxEntryBytes ?? ZIP_LIMITS.maxEntryBytes,
|
|
170
|
+
maxEntries: options.maxEntries ?? ZIP_LIMITS.maxEntries,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function assertWithinLimit(value, limit, message) {
|
|
175
|
+
if (!Number.isFinite(limit) || limit < 0) {
|
|
176
|
+
throw new Error('invalid zip read limit');
|
|
177
|
+
}
|
|
178
|
+
if (value > limit) throw new Error(message);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function readZipBuffer(input, options = {}) {
|
|
159
182
|
const buffer = Buffer.isBuffer(input) ? input : Buffer.from(input);
|
|
183
|
+
const limits = readLimits(options);
|
|
184
|
+
assertWithinLimit(
|
|
185
|
+
buffer.length,
|
|
186
|
+
limits.maxZipBytes,
|
|
187
|
+
`refusing zip: archive size ${buffer.length} bytes exceeds ${limits.maxZipBytes} byte limit`,
|
|
188
|
+
);
|
|
160
189
|
const endOffset = findEndOfCentralDirectory(buffer);
|
|
161
190
|
const entryCount = buffer.readUInt16LE(endOffset + 10);
|
|
162
191
|
const centralSize = buffer.readUInt32LE(endOffset + 12);
|
|
163
192
|
const centralOffset = buffer.readUInt32LE(endOffset + 16);
|
|
193
|
+
assertWithinLimit(
|
|
194
|
+
entryCount,
|
|
195
|
+
limits.maxEntries,
|
|
196
|
+
`refusing zip: ${entryCount} entries exceeds ${limits.maxEntries} entry limit`,
|
|
197
|
+
);
|
|
164
198
|
assertReadable(buffer, centralOffset, centralSize, 'central directory');
|
|
165
199
|
|
|
166
|
-
const
|
|
200
|
+
const metadata = [];
|
|
201
|
+
const centralEnd = centralOffset + centralSize;
|
|
202
|
+
let declaredUnpackedBytes = 0;
|
|
167
203
|
let cursor = centralOffset;
|
|
168
204
|
for (let i = 0; i < entryCount; i += 1) {
|
|
169
|
-
|
|
205
|
+
if (cursor + 46 > centralEnd) {
|
|
206
|
+
throw new Error('invalid zip: truncated central directory entry');
|
|
207
|
+
}
|
|
170
208
|
if (buffer.readUInt32LE(cursor) !== CENTRAL_DIRECTORY_HEADER) {
|
|
171
209
|
throw new Error('invalid zip: malformed central directory');
|
|
172
210
|
}
|
|
173
211
|
|
|
174
212
|
const flags = buffer.readUInt16LE(cursor + 8);
|
|
175
213
|
const method = buffer.readUInt16LE(cursor + 10);
|
|
214
|
+
const expectedCrc = buffer.readUInt32LE(cursor + 16);
|
|
176
215
|
const compressedSize = buffer.readUInt32LE(cursor + 20);
|
|
177
216
|
const uncompressedSize = buffer.readUInt32LE(cursor + 24);
|
|
178
217
|
const nameLength = buffer.readUInt16LE(cursor + 28);
|
|
@@ -180,7 +219,9 @@ function readZipBuffer(input) {
|
|
|
180
219
|
const commentLength = buffer.readUInt16LE(cursor + 32);
|
|
181
220
|
const localOffset = buffer.readUInt32LE(cursor + 42);
|
|
182
221
|
const nameStart = cursor + 46;
|
|
183
|
-
|
|
222
|
+
if (nameStart + nameLength + extraLength + commentLength > centralEnd) {
|
|
223
|
+
throw new Error('invalid zip: truncated central directory name');
|
|
224
|
+
}
|
|
184
225
|
const name = buffer.slice(nameStart, nameStart + nameLength).toString('utf8');
|
|
185
226
|
cursor = nameStart + nameLength + extraLength + commentLength;
|
|
186
227
|
|
|
@@ -189,6 +230,39 @@ function readZipBuffer(input) {
|
|
|
189
230
|
throw new Error(`invalid zip: unsupported compression method ${method} for ${name}`);
|
|
190
231
|
}
|
|
191
232
|
|
|
233
|
+
assertWithinLimit(
|
|
234
|
+
uncompressedSize,
|
|
235
|
+
limits.maxEntryBytes,
|
|
236
|
+
`refusing zip: entry ${name} declares ${uncompressedSize} unpacked bytes, exceeding ${limits.maxEntryBytes} byte entry limit`,
|
|
237
|
+
);
|
|
238
|
+
declaredUnpackedBytes += uncompressedSize;
|
|
239
|
+
assertWithinLimit(
|
|
240
|
+
declaredUnpackedBytes,
|
|
241
|
+
limits.maxUnpackedBytes,
|
|
242
|
+
`refusing zip: declared unpacked size ${declaredUnpackedBytes} bytes exceeds ${limits.maxUnpackedBytes} byte limit`,
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
metadata.push({
|
|
246
|
+
name,
|
|
247
|
+
flags,
|
|
248
|
+
method,
|
|
249
|
+
expectedCrc,
|
|
250
|
+
compressedSize,
|
|
251
|
+
uncompressedSize,
|
|
252
|
+
localOffset,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const entries = [];
|
|
257
|
+
for (const entry of metadata) {
|
|
258
|
+
const {
|
|
259
|
+
name,
|
|
260
|
+
method,
|
|
261
|
+
expectedCrc,
|
|
262
|
+
compressedSize,
|
|
263
|
+
uncompressedSize,
|
|
264
|
+
localOffset,
|
|
265
|
+
} = entry;
|
|
192
266
|
assertReadable(buffer, localOffset, 30, 'local file header');
|
|
193
267
|
if (buffer.readUInt32LE(localOffset) !== LOCAL_FILE_HEADER) {
|
|
194
268
|
throw new Error(`invalid zip: missing local header for ${name}`);
|
|
@@ -198,18 +272,31 @@ function readZipBuffer(input) {
|
|
|
198
272
|
const dataStart = localOffset + 30 + localNameLength + localExtraLength;
|
|
199
273
|
assertReadable(buffer, dataStart, compressedSize, `file data for ${name}`);
|
|
200
274
|
const compressed = buffer.slice(dataStart, dataStart + compressedSize);
|
|
201
|
-
|
|
275
|
+
let data;
|
|
276
|
+
try {
|
|
277
|
+
data = method === STORE
|
|
278
|
+
? Buffer.from(compressed)
|
|
279
|
+
: zlib.inflateRawSync(compressed, { maxOutputLength: Math.max(1, uncompressedSize) });
|
|
280
|
+
} catch (error) {
|
|
281
|
+
if (error && error.code === 'ERR_BUFFER_TOO_LARGE') {
|
|
282
|
+
throw new Error(`invalid zip: inflated data exceeds declared size for ${name}`);
|
|
283
|
+
}
|
|
284
|
+
throw new Error(`invalid zip: could not inflate ${name}: ${error.message}`);
|
|
285
|
+
}
|
|
202
286
|
if (data.length !== uncompressedSize) {
|
|
203
287
|
throw new Error(`invalid zip: size mismatch for ${name}`);
|
|
204
288
|
}
|
|
289
|
+
if (crc32(data) !== expectedCrc) {
|
|
290
|
+
throw new Error(`invalid zip: checksum mismatch for ${name}`);
|
|
291
|
+
}
|
|
205
292
|
entries.push({ name, data });
|
|
206
293
|
}
|
|
207
294
|
|
|
208
295
|
return entries;
|
|
209
296
|
}
|
|
210
297
|
|
|
211
|
-
function readZipFile(filePath) {
|
|
212
|
-
return readZipBuffer(fs.readFileSync(filePath));
|
|
298
|
+
function readZipFile(filePath, options = {}) {
|
|
299
|
+
return readZipBuffer(fs.readFileSync(filePath), options);
|
|
213
300
|
}
|
|
214
301
|
|
|
215
302
|
module.exports = {
|
|
@@ -217,5 +304,5 @@ module.exports = {
|
|
|
217
304
|
writeZipFile,
|
|
218
305
|
readZipBuffer,
|
|
219
306
|
readZipFile,
|
|
220
|
-
|
|
307
|
+
ZIP_LIMITS,
|
|
221
308
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "atris",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.40.0",
|
|
4
4
|
"description": "you say what you want in plain words. atris builds it, checks it, and shows you proof.",
|
|
5
5
|
"main": "bin/atris.js",
|
|
6
6
|
"bin": {
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
"test": "node --test",
|
|
58
58
|
"test:fast": "xargs node --test < test/fast-tests.txt",
|
|
59
59
|
"lint:decks": "node scripts/lint-all-decks.js",
|
|
60
|
+
"audit:markdown-whitespace": "node scripts/audit-markdown-whitespace.js",
|
|
60
61
|
"publish:release": "node scripts/publish-atris-release.js",
|
|
61
62
|
"prepare": "cp scripts/pre-commit .git/hooks/pre-commit 2>/dev/null && cp scripts/commit-msg .git/hooks/commit-msg 2>/dev/null && cp scripts/prepare-commit-msg .git/hooks/prepare-commit-msg 2>/dev/null && chmod +x .git/hooks/pre-commit .git/hooks/commit-msg .git/hooks/prepare-commit-msg || true"
|
|
62
63
|
},
|
|
@@ -18,6 +18,15 @@ Keep this file aligned with `atris/persona.md`.
|
|
|
18
18
|
- Concrete examples over abstractions
|
|
19
19
|
- Cite the source when answering domain questions
|
|
20
20
|
|
|
21
|
+
## The Way Of Talking (every message a human reads)
|
|
22
|
+
|
|
23
|
+
- Plain words. Say what happened and what it means for the reader — cause and effect, not machinery.
|
|
24
|
+
- No task codes, commit hashes, or internal system names in the message body. If the reader needs a code to act, put ONE copyable command at the end.
|
|
25
|
+
- No insider terms without defining them in the same breath.
|
|
26
|
+
- One idea per line. Outcome first. Detail lives in files, not the message.
|
|
27
|
+
- Lists: spell the numbers as words (One. Two. Three.), each item its own paragraph with a blank line between. Never markdown numbered lists — they render cramped.
|
|
28
|
+
- The test: a sharp, tired non-engineer follows it on first read. If not, rewrite.
|
|
29
|
+
|
|
21
30
|
## Anti-patterns
|
|
22
31
|
|
|
23
32
|
- No em dashes in outbound copy
|