@intentic/claude-plugin 1.317.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.
@@ -0,0 +1,1658 @@
1
+ import { createRequire as __intenticRequire } from 'node:module'; const require = __intenticRequire(import.meta.url);
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __commonJS = (cb, mod) => function __require() {
9
+ try {
10
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
11
+ } catch (e) {
12
+ throw mod = 0, e;
13
+ }
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
31
+
32
+ // ../../node_modules/.pnpm/ignore@7.0.10/node_modules/ignore/index.js
33
+ var require_ignore = __commonJS({
34
+ "../../node_modules/.pnpm/ignore@7.0.10/node_modules/ignore/index.js"(exports, module) {
35
+ function makeArray(subject) {
36
+ return Array.isArray(subject) ? subject : [subject];
37
+ }
38
+ var UNDEFINED = void 0;
39
+ var EMPTY = "";
40
+ var SPACE = " ";
41
+ var ESCAPE = "\\";
42
+ var REGEX_LITERAL_SPECIAL = /[.*+?()[\]{}^$|\\/]/;
43
+ var REGEX_TEST_BLANK_LINE = /^\uFEFF? *$/;
44
+ var REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/;
45
+ var REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/;
46
+ var REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/;
47
+ var REGEX_SPLITALL_CRLF = /\r?\n/g;
48
+ var DOUBLE_SLASH = "//";
49
+ var SLASH_CODE = 47;
50
+ var DOT_CODE = 46;
51
+ var SLASH = "/";
52
+ var TMP_KEY_IGNORE = "node-ignore";
53
+ if (typeof Symbol !== "undefined") {
54
+ TMP_KEY_IGNORE = /* @__PURE__ */ Symbol.for("node-ignore");
55
+ }
56
+ var KEY_IGNORE = TMP_KEY_IGNORE;
57
+ var define = (object, key, value) => {
58
+ Object.defineProperty(object, key, { value });
59
+ return value;
60
+ };
61
+ var RETURN_FALSE = () => false;
62
+ var cleanRangeBackSlash = (slashes) => {
63
+ const { length } = slashes;
64
+ return slashes.slice(0, length - length % 2);
65
+ };
66
+ var POSIX_CLASSES = {
67
+ alnum: "0-9A-Za-z",
68
+ alpha: "A-Za-z",
69
+ blank: " \\t",
70
+ cntrl: "\\x00-\\x1f\\x7f",
71
+ digit: "0-9",
72
+ graph: "!-.0-~",
73
+ lower: "a-z",
74
+ print: " -.0-~",
75
+ punct: "!-.:-@\\[-`{-~",
76
+ // git's `sane-ctype.h` classifies \v and \f as control, not space,
77
+ // unlike C's `isspace`
78
+ space: " \\t\\n\\r",
79
+ upper: "A-Z",
80
+ xdigit: "0-9A-Fa-f"
81
+ };
82
+ var CLASS_MEMBERS_TO_ESCAPE = "\\]^-[";
83
+ var escapeMember = (char) => CLASS_MEMBERS_TO_ESCAPE.indexOf(char) < 0 ? char : ESCAPE + char;
84
+ var NON_SLASH = "(?!\\/)";
85
+ var classSource = (negated, body) => {
86
+ if (negated) {
87
+ return `[^\\/${body}]`;
88
+ }
89
+ const source = `[${body}]`;
90
+ return new RegExp(source).test("/") ? NON_SLASH + source : source;
91
+ };
92
+ var scanBracket = (pattern, start) => {
93
+ const { length } = pattern;
94
+ let index = start + 1;
95
+ let negated = EMPTY;
96
+ const lead = pattern[index];
97
+ if (lead === "!" || lead === "^") {
98
+ negated = "^";
99
+ index++;
100
+ }
101
+ let body = EMPTY;
102
+ let prev = EMPTY;
103
+ for (; ; ) {
104
+ const char = pattern[index];
105
+ if (char === UNDEFINED) {
106
+ return null;
107
+ }
108
+ if (char === ESCAPE) {
109
+ const escaped = pattern[index + 1];
110
+ if (escaped === UNDEFINED) {
111
+ return null;
112
+ }
113
+ body += escapeMember(escaped);
114
+ prev = escaped;
115
+ index++;
116
+ } else if (char === "-" && prev && index + 1 < length && pattern[index + 1] !== "]") {
117
+ index++;
118
+ let to = pattern[index];
119
+ if (to === ESCAPE) {
120
+ to = pattern[index += 1];
121
+ }
122
+ if (prev <= to) {
123
+ body += `-${escapeMember(to)}`;
124
+ }
125
+ prev = EMPTY;
126
+ } else if (char === "[" && pattern[index + 1] === ":") {
127
+ const nameStart = index + 2;
128
+ let end = nameStart;
129
+ while (end < length && pattern[end] !== "]") {
130
+ end++;
131
+ }
132
+ if (end === length) {
133
+ return null;
134
+ }
135
+ if (end > nameStart && pattern[end - 1] === ":") {
136
+ const expanded = POSIX_CLASSES[pattern.slice(nameStart, end - 1)];
137
+ if (expanded === UNDEFINED) {
138
+ return null;
139
+ }
140
+ body += expanded;
141
+ prev = EMPTY;
142
+ index = end;
143
+ } else {
144
+ body += escapeMember("[");
145
+ prev = "[";
146
+ index = nameStart - 2;
147
+ }
148
+ } else {
149
+ body += escapeMember(char);
150
+ prev = char;
151
+ }
152
+ index++;
153
+ if (pattern[index] === "]") {
154
+ return {
155
+ end: index,
156
+ source: classSource(negated, body)
157
+ };
158
+ }
159
+ }
160
+ };
161
+ var NEVER_MATCH = "[]";
162
+ var PLACEHOLDER = "\0";
163
+ var REGEX_RESTORE_PLACEHOLDER = new RegExp(
164
+ `${PLACEHOLDER}(\\d+)${PLACEHOLDER}`,
165
+ "g"
166
+ );
167
+ var TRAILING_WILDCARD = "\uE000";
168
+ var extractBrackets = (pattern) => {
169
+ const sources = [];
170
+ const hold = (source) => `${PLACEHOLDER}${sources.push(source) - 1}${PLACEHOLDER}`;
171
+ const { length } = pattern;
172
+ let out = EMPTY;
173
+ let index = 0;
174
+ while (index < length) {
175
+ const char = pattern[index];
176
+ if (char === ESCAPE) {
177
+ const escaped = pattern[index + 1];
178
+ if (escaped === "*" || escaped === "[" || escaped === SPACE || escaped === ESCAPE) {
179
+ out += pattern.slice(index, index + 2);
180
+ } else {
181
+ out += hold(
182
+ REGEX_LITERAL_SPECIAL.test(escaped) ? ESCAPE + escaped : escaped
183
+ );
184
+ }
185
+ index += 2;
186
+ } else if (char === PLACEHOLDER) {
187
+ out += hold(`[${PLACEHOLDER}]`);
188
+ index++;
189
+ } else if (char === "[") {
190
+ const scanned = scanBracket(pattern, index);
191
+ if (scanned === null) {
192
+ out += hold(NEVER_MATCH);
193
+ index = length;
194
+ } else {
195
+ out += hold(scanned.source);
196
+ index = scanned.end + 1;
197
+ }
198
+ } else {
199
+ out += char;
200
+ index++;
201
+ }
202
+ }
203
+ return {
204
+ source: out,
205
+ sources
206
+ };
207
+ };
208
+ var DIRECT = null;
209
+ var REGEX_INNER_SLASH = /\/(?!$)/;
210
+ var REPLACERS = [
211
+ [
212
+ // Remove BOM
213
+ // TODO:
214
+ // Other similar zero-width characters?
215
+ /^\uFEFF/,
216
+ () => EMPTY,
217
+ "\uFEFF"
218
+ ],
219
+ [
220
+ // A trailing line terminator, left on when a whole file's contents are
221
+ // added as one pattern rather than split into lines. git never sees one
222
+ // -- it reads a `.gitignore` line by line -- so it is not part of the
223
+ // pattern and is dropped here, apart from the trailing-space trimming,
224
+ // which follows git in touching spaces and nothing else.
225
+ /[\r\n]+$/,
226
+ () => EMPTY
227
+ ],
228
+ // > Trailing spaces are ignored unless they are quoted with backslash ("\")
229
+ [
230
+ // Only spaces, never tabs or other whitespace: git trims a trailing run
231
+ // of `' '` and nothing else (dir.c, `trim_trailing_spaces`, a single
232
+ // `case ' '`), so a pattern ending in a tab keeps it as a literal.
233
+ // (a\ ) -> (a )
234
+ // (a ) -> (a)
235
+ // (a ) -> (a)
236
+ // (a \ ) -> (a )
237
+ /((?:\\\\)*?)(\\? +)$/,
238
+ (_, m1, m2) => m1 + (m2.indexOf("\\") === 0 ? SPACE : EMPTY)
239
+ ],
240
+ // Replace (\ ) with ' '
241
+ // Only a space: an escaped tab or other whitespace is already a literal by
242
+ // the time it reaches here, and a bare tab must be left as one, not turned
243
+ // into a space.
244
+ // (\ ) -> ' '
245
+ // (\\ ) -> '\\ '
246
+ // (\\\ ) -> '\\ '
247
+ [
248
+ /(\\+?) /g,
249
+ (_, m1) => {
250
+ const { length } = m1;
251
+ return m1.slice(0, length - length % 2) + SPACE;
252
+ }
253
+ ],
254
+ // Escape metacharacters
255
+ // which is written down by users but means special for regular expressions.
256
+ // > There are 12 characters with special meanings:
257
+ // > - the backslash \,
258
+ // > - the caret ^,
259
+ // > - the dollar sign $,
260
+ // > - the period or dot .,
261
+ // > - the vertical bar or pipe symbol |,
262
+ // > - the question mark ?,
263
+ // > - the asterisk or star *,
264
+ // > - the plus sign +,
265
+ // > - the opening parenthesis (,
266
+ // > - the closing parenthesis ),
267
+ // > - and the opening square bracket [,
268
+ // > - the opening curly brace {,
269
+ // > These special characters are often called "metacharacters".
270
+ [
271
+ /[\\$.|*+(){^]/g,
272
+ (match) => `\\${match}`
273
+ ],
274
+ [
275
+ // > a question mark (?) matches a single character
276
+ /(?!\\)\?/g,
277
+ () => "[^/]",
278
+ "?"
279
+ ],
280
+ // leading slash
281
+ [
282
+ // > A leading slash matches the beginning of the pathname.
283
+ // > For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".
284
+ // A leading slash matches the beginning of the pathname
285
+ /^\//,
286
+ () => "^",
287
+ SLASH
288
+ ],
289
+ // replace special metacharacter slash after the leading slash
290
+ [
291
+ /\//g,
292
+ () => "\\/",
293
+ SLASH
294
+ ],
295
+ [
296
+ // > A leading "**" followed by a slash means match in all directories.
297
+ // > For example, "**/foo" matches file or directory "foo" anywhere,
298
+ // > the same as pattern "foo".
299
+ // > "**/foo/bar" matches file or directory "bar" anywhere that is directly
300
+ // > under directory "foo".
301
+ // Notice that the '*'s have been replaced as '\\*'
302
+ /^\^*(?:\\\*\\\*\\\/)+/,
303
+ // '**/foo' <-> 'foo'
304
+ () => "^(?:.*\\/)?",
305
+ "*"
306
+ ],
307
+ // starting
308
+ [
309
+ // there will be no leading '/'
310
+ // (which has been replaced by section "leading slash")
311
+ // If starts with '**', adding a '^' to the regular expression also works
312
+ DIRECT,
313
+ (source, pattern) => {
314
+ if (!source || source[0] === "^") {
315
+ return source;
316
+ }
317
+ const anchor = !REGEX_INNER_SLASH.test(pattern) ? "(?:^|\\/)" : "^";
318
+ return anchor + source;
319
+ }
320
+ ],
321
+ // two globstars
322
+ [
323
+ // Use lookahead assertions so that we could match more than one `'/**'`
324
+ /\\\/\\\*\\\*(?=\\\/|$)/g,
325
+ // Zero, one or several directories
326
+ // should not use '*', or it will be replaced by the next replacer
327
+ // Check if it is not the last `'/**'`
328
+ (_, index, str) => index + 6 < str.length ? str.slice(index + 6) === "\\/" ? "(?:\\/[^\\/]+)+" : "(?:\\/[^\\/]+)*" : "\\/.+",
329
+ "*"
330
+ ],
331
+ // normal intermediate wildcards
332
+ [
333
+ // Never replace escaped '*'
334
+ // ignore rule '\*' will match the path '*'
335
+ // 'abc.*/' -> go
336
+ // 'abc.*' -> skip this rule,
337
+ // coz trailing single wildcard will be handed by [trailing wildcard]
338
+ /(^|[^\\]+)(\\\*)+(?=.+)/g,
339
+ // '*.js' matches '.js'
340
+ // '*.js' doesn't match 'abc'
341
+ (_, p1, p2) => {
342
+ const unescaped = p2.replace(/\\\*/g, "[^\\/]*");
343
+ return p1 + unescaped;
344
+ },
345
+ "*"
346
+ ],
347
+ // trailing wildcard, held apart from a literal star
348
+ [
349
+ // The step above leaves a trailing `*` alone, so a single `\*` is all that
350
+ // can be left at the end here. Whether it is a wildcard or a literal
351
+ // turns on the backslashes the user put in front of it: the escaper has
352
+ // since doubled every one, so what stands here is those `2N` doubled
353
+ // backslashes and then the star's own escape. An even number of the
354
+ // original `N` leaves the star unescaped -- a wildcard -- and an odd
355
+ // number escapes it -- a literal. This runs while the two are still
356
+ // distinct, before the unescape steps below collapse the literal onto
357
+ // the very `\*` a wildcard leaves behind.
358
+ /(^|[^\\])((?:\\\\)*)\\\*$/,
359
+ (match, p1, p2) => (
360
+ // `p2` holds the doubled user backslashes; half of them is `N`.
361
+ p2.length / 2 % 2 === 0 ? p1 + p2 + TRAILING_WILDCARD : match
362
+ ),
363
+ "*"
364
+ ],
365
+ [
366
+ // unescape, revert step 3 except for back slash
367
+ // For example, if a user escape a '\\*',
368
+ // after step 3, the result will be '\\\\\\*'
369
+ /\\\\\\(?=[$.|*+(){^])/g,
370
+ () => ESCAPE,
371
+ ESCAPE + ESCAPE
372
+ ],
373
+ [
374
+ // '\\\\' -> '\\'
375
+ /\\\\/g,
376
+ () => ESCAPE,
377
+ ESCAPE + ESCAPE
378
+ ],
379
+ [
380
+ // Every real bracket expression -- POSIX classes included -- has already
381
+ // been held aside by `extractBrackets`, so the only `[` left in the
382
+ // pattern is an escaped, literal one.
383
+ // `\` is escaped by step 3
384
+ /\\\[([^\]/]*?)(\\*)($|\])/g,
385
+ // '\\[bar]' -> '\\\\[bar\\]'
386
+ (match, range, endEscape, close) => `\\[${range}${cleanRangeBackSlash(endEscape)}${close}`,
387
+ "["
388
+ ],
389
+ // ending
390
+ [
391
+ // 'js' will not match 'js.'
392
+ // 'ab' will not match 'abc'
393
+ DIRECT,
394
+ // WTF!
395
+ // https://git-scm.com/docs/gitignore
396
+ // changes in [2.22.1](https://git-scm.com/docs/gitignore/2.22.1)
397
+ // which re-fixes #24, #38
398
+ // > If there is a separator at the end of the pattern then the pattern
399
+ // > will only match directories, otherwise the pattern can match both
400
+ // > files and directories.
401
+ // 'js*' will not match 'a.js'
402
+ // 'js/' will not match 'a.js'
403
+ // 'js' will match 'a.js' and 'a.js/'
404
+ (source) => {
405
+ const last = source[source.length - 1];
406
+ if (!last || last === TRAILING_WILDCARD) {
407
+ return source;
408
+ }
409
+ return last === SLASH ? `${source}$` : `${source}(?=$|\\/$)`;
410
+ }
411
+ ]
412
+ ];
413
+ var REGEX_REPLACE_TRAILING_WILDCARD = /(^|\\\/)?\uE000$/;
414
+ var MODE_IGNORE = "regex";
415
+ var MODE_CHECK_IGNORE = "checkRegex";
416
+ var UNDERSCORE = "_";
417
+ var TRAILING_WILD_CARD_REPLACERS = {
418
+ [MODE_IGNORE](_, p1) {
419
+ const prefix = p1 ? `${p1}[^/]+` : "[^/]*";
420
+ return `${prefix}(?=$|\\/$)`;
421
+ },
422
+ [MODE_CHECK_IGNORE](_, p1) {
423
+ const prefix = p1 ? `${p1}[^/]*` : "[^/]*";
424
+ return `${prefix}(?=$|\\/$)`;
425
+ }
426
+ };
427
+ var WILDCARD = "[^\\/]*";
428
+ var separatorAfter = (run, at) => {
429
+ let separator = EMPTY;
430
+ for (let index = at + 1; index < run.length && !run[index].wildcard; index++) {
431
+ separator += run[index].single;
432
+ }
433
+ return separator;
434
+ };
435
+ var pinWildcards = (source) => {
436
+ if (source.indexOf(WILDCARD) < 0) {
437
+ return source;
438
+ }
439
+ const tokens = [];
440
+ const { length } = source;
441
+ let index = 0;
442
+ while (index < length) {
443
+ const char = source[index];
444
+ if (source.startsWith(WILDCARD, index)) {
445
+ tokens.push({ wildcard: true });
446
+ index += WILDCARD.length;
447
+ } else if (char === "[") {
448
+ let end = index + 1;
449
+ if (source[end] === "^") {
450
+ end++;
451
+ }
452
+ if (source[end] === "]") {
453
+ end++;
454
+ }
455
+ while (end < length && source[end] !== "]") {
456
+ end += source[end] === ESCAPE ? 2 : 1;
457
+ }
458
+ end++;
459
+ tokens.push({ single: source.slice(index, end) });
460
+ index = end;
461
+ } else if (char === ESCAPE) {
462
+ tokens.push({ single: source.slice(index, index + 2) });
463
+ index += 2;
464
+ } else if (char === "(") {
465
+ let depth = 0;
466
+ let end = index;
467
+ do {
468
+ if (source[end] === ESCAPE) {
469
+ end++;
470
+ } else if (source[end] === "(") {
471
+ depth++;
472
+ } else if (source[end] === ")") {
473
+ depth--;
474
+ }
475
+ end++;
476
+ } while (end < length && depth > 0);
477
+ if ("*+?".indexOf(source[end]) >= 0) {
478
+ end++;
479
+ }
480
+ tokens.push({ boundary: source.slice(index, end) });
481
+ index = end;
482
+ } else if (char === "^" || char === "$") {
483
+ tokens.push({ boundary: char });
484
+ index++;
485
+ } else {
486
+ tokens.push({ single: char });
487
+ index++;
488
+ }
489
+ }
490
+ let out = EMPTY;
491
+ let run = [];
492
+ const flush = () => {
493
+ let lastWildcard;
494
+ run.forEach((token, at) => {
495
+ if (token.wildcard) {
496
+ lastWildcard = at;
497
+ }
498
+ });
499
+ run.forEach((token, at) => {
500
+ if (!token.wildcard) {
501
+ out += token.single;
502
+ return;
503
+ }
504
+ out += at === lastWildcard ? WILDCARD : `(?:(?!${separatorAfter(run, at)})[^\\/])*`;
505
+ });
506
+ run = [];
507
+ };
508
+ tokens.forEach((token) => {
509
+ if (token.boundary === void 0) {
510
+ run.push(token);
511
+ return;
512
+ }
513
+ flush();
514
+ out += token.boundary;
515
+ });
516
+ flush();
517
+ return out;
518
+ };
519
+ var makeRegexPrefix = (pattern) => {
520
+ const { source, sources } = extractBrackets(pattern);
521
+ const replaced = REPLACERS.reduce(
522
+ // A pass whose matcher finds nothing hands back the very string it was
523
+ // given, so asking first costs a search and saves a rewrite. Ten of the
524
+ // fifteen passes never fire for a typical .gitignore line, and between
525
+ // them they were 45% of this chain.
526
+ (prev, [matcher, replacer, required]) => {
527
+ if (matcher === DIRECT) {
528
+ return replacer(prev, pattern);
529
+ }
530
+ if (required !== UNDEFINED && prev.indexOf(required) < 0) {
531
+ return prev;
532
+ }
533
+ return matcher.test(prev) ? prev.replace(matcher, replacer.bind(pattern)) : prev;
534
+ },
535
+ source
536
+ );
537
+ return sources.length ? replaced.replace(
538
+ REGEX_RESTORE_PLACEHOLDER,
539
+ (match, index) => sources[index]
540
+ ) : replaced;
541
+ };
542
+ var matchesBasename = (body) => {
543
+ const index = body.indexOf(SLASH);
544
+ return index < 0 || index === body.length - 1;
545
+ };
546
+ var basenameOf = (path) => {
547
+ const end = path.length - 1;
548
+ const index = path.lastIndexOf(
549
+ SLASH,
550
+ path[end] === SLASH ? end - 1 : end
551
+ );
552
+ return index < 0 ? path : path.slice(index + 1);
553
+ };
554
+ var parentOf = (path) => {
555
+ if (path.charCodeAt(0) === SLASH_CODE || path.indexOf(DOUBLE_SLASH) >= 0) {
556
+ const slices = path.split(SLASH).filter(Boolean);
557
+ slices.pop();
558
+ return slices.length ? slices.join(SLASH) + SLASH : EMPTY;
559
+ }
560
+ const end = path.length - 1;
561
+ const cut = path.lastIndexOf(
562
+ SLASH,
563
+ path.charCodeAt(end) === SLASH_CODE ? end - 1 : end
564
+ );
565
+ return cut < 0 ? EMPTY : path.slice(0, cut + 1);
566
+ };
567
+ var isString = (subject) => typeof subject === "string";
568
+ var checkPattern = (pattern) => pattern && isString(pattern) && !REGEX_TEST_BLANK_LINE.test(pattern) && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern) && pattern.indexOf("#") !== 0;
569
+ var splitPattern = (pattern) => pattern.split(REGEX_SPLITALL_CRLF).filter(Boolean);
570
+ var IgnoreRule = class {
571
+ constructor(pattern, mark, body, ignoreCase, negative, prefix) {
572
+ this.pattern = pattern;
573
+ this.mark = mark;
574
+ this.negative = negative;
575
+ define(this, "body", body);
576
+ define(this, "ignoreCase", ignoreCase);
577
+ define(this, "regexPrefix", prefix);
578
+ }
579
+ // Worked out on first use and kept behind an own property, the way `regex`
580
+ // caches itself in `_regex`. Deciding it in the constructor instead would
581
+ // add a fourth `defineProperty` to every rule ever built, which cost 4% of
582
+ // every compile -- including the compiles of rules that are never matched
583
+ // against anything.
584
+ get _basenameOnly() {
585
+ return define(this, "_basenameOnly", matchesBasename(this.body));
586
+ }
587
+ get regex() {
588
+ const key = UNDERSCORE + MODE_IGNORE;
589
+ if (this[key]) {
590
+ return this[key];
591
+ }
592
+ return this._make(MODE_IGNORE, key);
593
+ }
594
+ get checkRegex() {
595
+ const key = UNDERSCORE + MODE_CHECK_IGNORE;
596
+ if (this[key]) {
597
+ return this[key];
598
+ }
599
+ return this._make(MODE_CHECK_IGNORE, key);
600
+ }
601
+ _make(mode, key) {
602
+ const str = pinWildcards(this.regexPrefix.replace(
603
+ REGEX_REPLACE_TRAILING_WILDCARD,
604
+ // It does not need to bind pattern
605
+ TRAILING_WILD_CARD_REPLACERS[mode]
606
+ ));
607
+ const regex = this.ignoreCase ? new RegExp(str, "i") : new RegExp(str);
608
+ return define(this, key, regex);
609
+ }
610
+ };
611
+ var createRule = ({
612
+ pattern,
613
+ mark
614
+ }, ignoreCase) => {
615
+ let negative = false;
616
+ let body = pattern;
617
+ if (body.indexOf("!") === 0) {
618
+ negative = true;
619
+ body = body.substr(1);
620
+ }
621
+ body = body.replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, "!").replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, "#");
622
+ const regexPrefix = makeRegexPrefix(body);
623
+ return new IgnoreRule(
624
+ pattern,
625
+ mark,
626
+ body,
627
+ ignoreCase,
628
+ negative,
629
+ regexPrefix
630
+ );
631
+ };
632
+ var RuleManager = class {
633
+ constructor(ignoreCase) {
634
+ this._ignoreCase = ignoreCase;
635
+ this._rules = [];
636
+ this._basenameCount = 0;
637
+ }
638
+ _add(pattern) {
639
+ if (pattern && pattern[KEY_IGNORE]) {
640
+ this._rules = this._rules.concat(pattern._rules._rules);
641
+ this._basenameCount += pattern._rules._basenameCount;
642
+ this._added = true;
643
+ return;
644
+ }
645
+ if (isString(pattern)) {
646
+ pattern = {
647
+ pattern
648
+ };
649
+ }
650
+ if (checkPattern(pattern.pattern)) {
651
+ const rule = createRule(pattern, this._ignoreCase);
652
+ this._added = true;
653
+ this._rules.push(rule);
654
+ if (matchesBasename(rule.body)) {
655
+ this._basenameCount++;
656
+ }
657
+ }
658
+ }
659
+ // @param {Array<string> | string | Ignore} pattern
660
+ add(pattern) {
661
+ this._added = false;
662
+ makeArray(
663
+ isString(pattern) ? splitPattern(pattern) : pattern
664
+ ).forEach(this._add, this);
665
+ return this._added;
666
+ }
667
+ // Test one single path without recursively checking parent directories
668
+ //
669
+ // - checkUnignored `boolean` whether should check if the path is unignored,
670
+ // setting `checkUnignored` to `false` could reduce additional
671
+ // path matching.
672
+ // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
673
+ // @returns {TestResult} true if a file is ignored
674
+ test(path, checkUnignored, mode) {
675
+ let ignored = false;
676
+ let unignored = false;
677
+ let matchedRule;
678
+ const rules = this._rules;
679
+ const { length } = rules;
680
+ const shortcut = this._basenameCount * 2 >= length;
681
+ const basename2 = shortcut ? basenameOf(path) : path;
682
+ for (let index = 0; index < length; index++) {
683
+ const rule = rules[index];
684
+ const { negative } = rule;
685
+ const skip = unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored;
686
+ if (!skip && rule[mode].test(
687
+ shortcut && rule._basenameOnly ? basename2 : path
688
+ )) {
689
+ ignored = !negative;
690
+ unignored = negative;
691
+ matchedRule = negative ? UNDEFINED : rule;
692
+ }
693
+ }
694
+ const ret = {
695
+ ignored,
696
+ unignored
697
+ };
698
+ if (matchedRule) {
699
+ ret.rule = matchedRule;
700
+ }
701
+ return ret;
702
+ }
703
+ };
704
+ var throwError = (message, Ctor) => {
705
+ throw new Ctor(message);
706
+ };
707
+ var checkPath = (path, originalPath, doThrow) => {
708
+ if (!isString(path)) {
709
+ return doThrow(
710
+ `path must be a string, but got \`${originalPath}\``,
711
+ TypeError
712
+ );
713
+ }
714
+ if (!path) {
715
+ return doThrow(`path must not be empty`, TypeError);
716
+ }
717
+ if (checkPath.isNotRelative(path)) {
718
+ const r = "`path.relative()`d";
719
+ return doThrow(
720
+ `path should be a ${r} string, but got "${originalPath}"`,
721
+ RangeError
722
+ );
723
+ }
724
+ return true;
725
+ };
726
+ var isNotRelative = (path) => {
727
+ const first = path.charCodeAt(0);
728
+ if (first === SLASH_CODE) {
729
+ return true;
730
+ }
731
+ if (first !== DOT_CODE) {
732
+ return false;
733
+ }
734
+ if (path.length === 1) {
735
+ return true;
736
+ }
737
+ const second = path.charCodeAt(1);
738
+ if (second === SLASH_CODE) {
739
+ return true;
740
+ }
741
+ if (second !== DOT_CODE) {
742
+ return false;
743
+ }
744
+ return path.length === 2 || path.charCodeAt(2) === SLASH_CODE;
745
+ };
746
+ checkPath.isNotRelative = isNotRelative;
747
+ checkPath.convert = (p) => p;
748
+ var Ignore = class {
749
+ constructor({
750
+ ignorecase = true,
751
+ ignoreCase = ignorecase,
752
+ allowRelativePaths = false
753
+ } = {}) {
754
+ define(this, KEY_IGNORE, true);
755
+ this._rules = new RuleManager(ignoreCase);
756
+ this._strictPathCheck = !allowRelativePaths;
757
+ this._initCache();
758
+ }
759
+ _initCache() {
760
+ this._ignoreCache = /* @__PURE__ */ Object.create(null);
761
+ this._testCache = /* @__PURE__ */ Object.create(null);
762
+ }
763
+ add(pattern) {
764
+ if (this._rules.add(pattern)) {
765
+ this._initCache();
766
+ }
767
+ return this;
768
+ }
769
+ // legacy
770
+ addPattern(pattern) {
771
+ return this.add(pattern);
772
+ }
773
+ // @returns {TestResult}
774
+ _test(originalPath, cache2, checkUnignored) {
775
+ const path = originalPath && checkPath.convert(originalPath);
776
+ checkPath(
777
+ path,
778
+ originalPath,
779
+ this._strictPathCheck ? throwError : RETURN_FALSE
780
+ );
781
+ return this._t(path, cache2, checkUnignored);
782
+ }
783
+ checkIgnore(path) {
784
+ if (path.charCodeAt(path.length - 1) !== SLASH_CODE) {
785
+ return this.test(path);
786
+ }
787
+ const parentPath = parentOf(path);
788
+ if (parentPath) {
789
+ const parent = this._t(parentPath, this._testCache, true);
790
+ if (parent.ignored) {
791
+ return parent;
792
+ }
793
+ }
794
+ return this._rules.test(path, false, MODE_CHECK_IGNORE);
795
+ }
796
+ _t(path, cache2, checkUnignored) {
797
+ if (path in cache2) {
798
+ return cache2[path];
799
+ }
800
+ const parentPath = parentOf(path);
801
+ const parent = parentPath ? this._t(parentPath, cache2, checkUnignored) : UNDEFINED;
802
+ return cache2[path] = parent && parent.ignored ? parent : this._rules.test(path, checkUnignored, MODE_IGNORE);
803
+ }
804
+ ignores(path) {
805
+ return this._test(path, this._ignoreCache, false).ignored;
806
+ }
807
+ createFilter() {
808
+ return (path) => !this.ignores(path);
809
+ }
810
+ filter(paths) {
811
+ return makeArray(paths).filter(this.createFilter());
812
+ }
813
+ // @returns {TestResult}
814
+ test(path) {
815
+ return this._test(path, this._testCache, true);
816
+ }
817
+ };
818
+ var factory = (options) => new Ignore(options);
819
+ var isPathValid = (path) => checkPath(path && checkPath.convert(path), path, RETURN_FALSE);
820
+ var setupWindows = () => {
821
+ const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
822
+ checkPath.convert = makePosix;
823
+ const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
824
+ checkPath.isNotRelative = (path) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path) || isNotRelative(path);
825
+ };
826
+ if (
827
+ // Detect `process` so that it can run in browsers.
828
+ typeof process !== "undefined" && process.platform === "win32"
829
+ ) {
830
+ setupWindows();
831
+ }
832
+ module.exports = factory;
833
+ factory.default = factory;
834
+ module.exports.isPathValid = isPathValid;
835
+ define(module.exports, /* @__PURE__ */ Symbol.for("setupWindows"), setupWindows);
836
+ }
837
+ });
838
+
839
+ // src/session-start.ts
840
+ import { appendFileSync as appendFileSync2, existsSync } from "node:fs";
841
+ import { join as join7 } from "node:path";
842
+
843
+ // ../agent-context/src/field-notes.ts
844
+ import { createHash } from "node:crypto";
845
+ import { readFileSync, statSync } from "node:fs";
846
+ var FIELD_NOTES_NOTE_TITLE = "Field notes for this sandbox";
847
+ var FIELD_NOTES_NOTE_HEADER = `## ${FIELD_NOTES_NOTE_TITLE}`;
848
+ var ALWAYS = ["meta"];
849
+ var ROW = /^(\d+),([a-z][a-z0-9_-]*),/;
850
+ var TOP_LEVEL = /^([a-z][a-z0-9_]*)(\[|:)/;
851
+ var blocksOf = (lines) => {
852
+ const opens = [];
853
+ for (const [at, line] of lines.entries()) {
854
+ const key = TOP_LEVEL.exec(line)?.[1];
855
+ if (key !== void 0) {
856
+ opens.push({ key, at });
857
+ }
858
+ }
859
+ const blocks = /* @__PURE__ */ new Map();
860
+ for (const [index, open] of opens.entries()) {
861
+ blocks.set(open.key, lines.slice(open.at, opens[index + 1]?.at).join("\n").trimEnd());
862
+ }
863
+ return blocks;
864
+ };
865
+ var indexOf = (block) => {
866
+ if (block === void 0) {
867
+ return void 0;
868
+ }
869
+ const rows = [];
870
+ for (const line of block.split("\n").slice(1)) {
871
+ const trimmed = line.trim();
872
+ if (trimmed === "") {
873
+ continue;
874
+ }
875
+ const row = ROW.exec(trimmed);
876
+ if (row?.[1] === void 0 || row[2] === void 0) {
877
+ return void 0;
878
+ }
879
+ rows.push({ rank: Number(row[1]), id: row[2] });
880
+ }
881
+ return rows.length === 0 ? void 0 : rows.toSorted((left, right) => left.rank - right.rank);
882
+ };
883
+ var withinBudget = (sections, spent, budget) => {
884
+ const kept = [];
885
+ let used = spent;
886
+ for (const section of sections) {
887
+ const cost = section.text.length + 1;
888
+ if (used + cost > budget) {
889
+ break;
890
+ }
891
+ used += cost;
892
+ kept.push(section);
893
+ }
894
+ return kept;
895
+ };
896
+ var readFieldNotesFile = (file) => {
897
+ try {
898
+ const text = readFileSync(file, "utf8");
899
+ return text.trim() === "" ? void 0 : { text, writtenAt: statSync(file).mtimeMs };
900
+ } catch {
901
+ return void 0;
902
+ }
903
+ };
904
+ var fieldNotes = ({ file: path, budget, onUnreadable, title = FIELD_NOTES_NOTE_TITLE }) => {
905
+ const file = readFieldNotesFile(path);
906
+ if (file === void 0) {
907
+ return void 0;
908
+ }
909
+ const lines = file.text.split("\n");
910
+ const blocks = blocksOf(lines);
911
+ const index = indexOf(blocks.get("priority"));
912
+ if (index === void 0) {
913
+ onUnreadable?.(`no readable \`priority\` table, so there is no order to send it in`);
914
+ return void 0;
915
+ }
916
+ const missing = index.filter(({ id }) => !blocks.has(id)).map(({ id }) => id);
917
+ if (missing.length > 0) {
918
+ onUnreadable?.(`the index names sections the file does not carry: ${missing.join(", ")}`);
919
+ return void 0;
920
+ }
921
+ const head = ALWAYS.flatMap((key) => {
922
+ const block = blocks.get(key);
923
+ return block === void 0 ? [] : [block];
924
+ });
925
+ const ranked = index.flatMap(({ id, rank }) => {
926
+ const text2 = blocks.get(id);
927
+ return text2 === void 0 ? [] : [{ id, rank, text: text2 }];
928
+ });
929
+ const header = `## ${title}`;
930
+ const spent = header.length + head.reduce((sum, block) => sum + block.length + 1, 0);
931
+ const kept = withinBudget(ranked, spent, budget);
932
+ const dropped = ranked.filter((section) => !kept.includes(section));
933
+ const disclosure = dropped.length === 0 ? `# every section of ${path} is below.` : `# ranks ${kept.length + 1}-${ranked.length} of ${path} are NOT below (${dropped.map((section) => section.id).join(", ")}); read the file itself if a turn needs them.`;
934
+ const text = [header, "", disclosure, ...head, ...kept.map((section) => section.text)].join("\n");
935
+ return {
936
+ text,
937
+ chars: text.length,
938
+ revision: createHash("sha256").update(file.text).digest("hex").slice(0, 8),
939
+ ranksSent: kept.length,
940
+ ranksTotal: ranked.length,
941
+ writtenAt: file.writtenAt
942
+ };
943
+ };
944
+
945
+ // ../agent-context/src/workspace-map.ts
946
+ import { readdirSync, readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
947
+ import { basename, dirname, join, relative, sep } from "node:path";
948
+
949
+ // ../../_shared/workspace-ignore/src/index.ts
950
+ var import_ignore = __toESM(require_ignore(), 1);
951
+
952
+ // ../../_tools/constants/src/hosted-tiers.ts
953
+ var HOSTED_TIERS = [
954
+ { id: "free", name: "Free", cpuKind: "shared", cpus: 4, memoryMb: 4096, volumeGb: 10, monthlyHours: 40, priceUsd: 0, flyHourUsd: 0.0329 },
955
+ { id: "standard", name: "Standard", cpuKind: "shared", cpus: 8, memoryMb: 8192, volumeGb: 25, monthlyHours: 220, priceUsd: 20, flyHourUsd: 0.0657 },
956
+ { id: "max", name: "Max", cpuKind: "shared", cpus: 8, memoryMb: 16384, volumeGb: 50, monthlyHours: 320, priceUsd: 50, flyHourUsd: 0.1234 }
957
+ ];
958
+ var FREE_TIER = HOSTED_TIERS[0];
959
+ var PAID_TIERS = HOSTED_TIERS.filter((tier) => tier.priceUsd > 0);
960
+
961
+ // ../../_tools/constants/src/index.ts
962
+ var REFERENCE_DIR = "refs";
963
+ var PUBLIC_DIR = "public";
964
+ var GOOGLE_CLIENT_ID = "481795963975-cq9msl6higcd91joidrfp8mjlkuq5fk3.apps.googleusercontent.com";
965
+ var GOOGLE_TOKEN_STORAGE_KEY = `intentic.gid.${GOOGLE_CLIENT_ID}`;
966
+
967
+ // ../../_shared/workspace-ignore/src/constants.ts
968
+ var GIT_DIR = ".git";
969
+ var IGNORED_DIRS = /* @__PURE__ */ new Set([
970
+ "node_modules",
971
+ GIT_DIR,
972
+ ".tmp",
973
+ "dist",
974
+ ".cache",
975
+ ".turbo",
976
+ ".next",
977
+ ".angular",
978
+ ".pnpm-store",
979
+ ".yarn",
980
+ ".venv",
981
+ "venv",
982
+ "__pycache__",
983
+ ".pytest_cache",
984
+ ".mypy_cache",
985
+ ".ruff_cache",
986
+ ".gradle"
987
+ ]);
988
+ var isSeparator = (char) => char === "/" || char === "\\";
989
+ var firstSegment = (relPath) => {
990
+ let start = 0;
991
+ while (isSeparator(relPath[start])) {
992
+ start++;
993
+ }
994
+ let end = start;
995
+ while (end < relPath.length && !isSeparator(relPath[end])) {
996
+ end++;
997
+ }
998
+ return relPath.slice(start, end);
999
+ };
1000
+ var isReferencePath = (relPath) => firstSegment(relPath) === REFERENCE_DIR;
1001
+ var isPublicPath = (relPath) => firstSegment(relPath) === PUBLIC_DIR;
1002
+
1003
+ // ../agent-context/src/workspace-map.ts
1004
+ var WORKSPACE_MAP_NOTE_HEADER = "## Map of this project";
1005
+ var MAX_NOTE_CHARS = 2800;
1006
+ var MAX_PURPOSE_CHARS = 100;
1007
+ var MAX_AREA_DEPTH = 4;
1008
+ var MAX_AREA_ENTRIES = 4e3;
1009
+ var MAX_AREAS = 24;
1010
+ var CONTAINER_MIN_CHILDREN = 3;
1011
+ var DOMINANT_SHARE = 0.5;
1012
+ var MAX_EXPANDED = 12;
1013
+ var MANIFESTS = ["package.json", "pyproject.toml", "Cargo.toml", "composer.json", "go.mod", "build.gradle", "pom.xml"];
1014
+ var posix = (path) => path.split(sep).join("/");
1015
+ var isBrowsable = (name, relPath) => !name.startsWith(".") && !IGNORED_DIRS.has(name) && !isReferencePath(relPath) && !isPublicPath(relPath);
1016
+ var childDirs = (dir, root) => {
1017
+ let entries;
1018
+ try {
1019
+ entries = readdirSync(dir, { withFileTypes: true });
1020
+ } catch {
1021
+ return [];
1022
+ }
1023
+ return entries.filter((entry) => entry.isDirectory() && isBrowsable(entry.name, posix(relative(root, join(dir, entry.name))))).map((entry) => entry.name).toSorted();
1024
+ };
1025
+ var readIfPresent = (path) => {
1026
+ try {
1027
+ return readFileSync2(path, "utf8");
1028
+ } catch {
1029
+ return void 0;
1030
+ }
1031
+ };
1032
+ var hasManifest = (dir) => MANIFESTS.some((name) => readIfPresent(join(dir, name)) !== void 0);
1033
+ var describeManifest = (dir, name) => {
1034
+ const source = readIfPresent(join(dir, name));
1035
+ if (source === void 0) {
1036
+ return void 0;
1037
+ }
1038
+ if (name.endsWith(".json")) {
1039
+ try {
1040
+ const description = JSON.parse(source).description;
1041
+ return typeof description === "string" && description.trim() !== "" ? description.trim() : void 0;
1042
+ } catch {
1043
+ return void 0;
1044
+ }
1045
+ }
1046
+ if (name === "go.mod") {
1047
+ const module = /^\s*module\s+(\S+)/m.exec(source)?.[1];
1048
+ return module === void 0 ? void 0 : `Go module ${module.split("/").slice(-2).join("/")}`;
1049
+ }
1050
+ const toml = /^\s*description\s*=\s*["'](.+?)["']\s*$/m.exec(source)?.[1];
1051
+ const xml = /<description>([^<]+)<\/description>/.exec(source)?.[1];
1052
+ const found = (toml ?? xml)?.trim();
1053
+ return found === void 0 || found === "" ? void 0 : found;
1054
+ };
1055
+ var describeReadme = (dir) => {
1056
+ const source = readIfPresent(join(dir, "README.md")) ?? readIfPresent(join(dir, "readme.md"));
1057
+ if (source === void 0) {
1058
+ return void 0;
1059
+ }
1060
+ const body = source.replace(/^---[\s\S]*?\n---\s*/, "");
1061
+ for (const raw of body.split("\n")) {
1062
+ const line = raw.trim();
1063
+ if (line === "" || line.startsWith("#") || line.startsWith("<") || line.startsWith(">") || line.startsWith("|")) {
1064
+ continue;
1065
+ }
1066
+ const prose = line.replace(/!\[[^\]]*\]\([^)]*\)/g, "").replace(/\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/[*_`]/g, "").trim();
1067
+ if (prose === "" || prose.startsWith("-") || prose.startsWith("*")) {
1068
+ continue;
1069
+ }
1070
+ return prose;
1071
+ }
1072
+ return void 0;
1073
+ };
1074
+ var clip = (text, max) => {
1075
+ const oneLine = text.replace(/\s+/g, " ").trim();
1076
+ if (oneLine.length <= max) {
1077
+ return oneLine;
1078
+ }
1079
+ const head = oneLine.slice(0, max);
1080
+ const lastSpace = head.lastIndexOf(" ");
1081
+ return `${(lastSpace > max / 2 ? head.slice(0, lastSpace) : head).replace(/[.,;:]$/, "")}\u2026`;
1082
+ };
1083
+ var purposeOf = (dir) => {
1084
+ for (const name of MANIFESTS) {
1085
+ const described = describeManifest(dir, name);
1086
+ if (described !== void 0) {
1087
+ return clip(described, MAX_PURPOSE_CHARS);
1088
+ }
1089
+ }
1090
+ const readme = describeReadme(dir);
1091
+ return readme === void 0 ? "" : clip(readme, MAX_PURPOSE_CHARS);
1092
+ };
1093
+ var measure = (dir, root) => {
1094
+ const extensions = /* @__PURE__ */ new Map();
1095
+ let files = 0;
1096
+ let visited = 0;
1097
+ const walk = (current, depth) => {
1098
+ if (depth > MAX_AREA_DEPTH || visited >= MAX_AREA_ENTRIES) {
1099
+ return;
1100
+ }
1101
+ let entries;
1102
+ try {
1103
+ entries = readdirSync(current, { withFileTypes: true });
1104
+ } catch {
1105
+ return;
1106
+ }
1107
+ for (const entry of entries) {
1108
+ if (visited >= MAX_AREA_ENTRIES) {
1109
+ return;
1110
+ }
1111
+ visited += 1;
1112
+ const child = join(current, entry.name);
1113
+ if (entry.isDirectory()) {
1114
+ if (isBrowsable(entry.name, posix(relative(root, child)))) {
1115
+ walk(child, depth + 1);
1116
+ }
1117
+ continue;
1118
+ }
1119
+ if (!entry.isFile() || entry.name.startsWith(".")) {
1120
+ continue;
1121
+ }
1122
+ files += 1;
1123
+ const dot = entry.name.lastIndexOf(".");
1124
+ if (dot > 0) {
1125
+ const ext = entry.name.slice(dot + 1).toLowerCase();
1126
+ if (ext.length <= 5) {
1127
+ extensions.set(ext, (extensions.get(ext) ?? 0) + 1);
1128
+ }
1129
+ }
1130
+ }
1131
+ };
1132
+ walk(dir, 0);
1133
+ const kinds = [...extensions.entries()].toSorted((left, right) => right[1] - left[1] || left[0].localeCompare(right[0])).slice(0, 2).map(([ext]) => ext);
1134
+ return { files, kinds };
1135
+ };
1136
+ var projectRootOf = (root, cwd) => {
1137
+ let current = cwd;
1138
+ for (; ; ) {
1139
+ try {
1140
+ statSync2(join(current, ".git"));
1141
+ return current;
1142
+ } catch {
1143
+ }
1144
+ if (current === root || current === dirname(current)) {
1145
+ return root;
1146
+ }
1147
+ const parent = dirname(current);
1148
+ if (relative(root, parent).startsWith("..")) {
1149
+ return root;
1150
+ }
1151
+ current = parent;
1152
+ }
1153
+ };
1154
+ var packagesIn = (dir, root) => {
1155
+ if (hasManifest(dir)) {
1156
+ return [];
1157
+ }
1158
+ const children = childDirs(dir, root);
1159
+ const bearing = children.filter((child) => hasManifest(join(dir, child)));
1160
+ return children.length >= CONTAINER_MIN_CHILDREN && bearing.length >= CONTAINER_MIN_CHILDREN ? bearing.map((child) => ({ name: child, dir: join(dir, child) })) : [];
1161
+ };
1162
+ var areaDirsOf = (projectRoot, root) => {
1163
+ const names = childDirs(projectRoot, root);
1164
+ const areas = names.map((name) => {
1165
+ const dir = join(projectRoot, name);
1166
+ return { name, dir, packages: packagesIn(dir, root) };
1167
+ });
1168
+ const shelf = areas.length <= 2 ? areas.find((area) => area.packages.length > 0) : void 0;
1169
+ return shelf === void 0 ? areas : shelf.packages.map((entry) => ({ name: `${shelf.name}/${entry.name}`, dir: entry.dir, packages: [] }));
1170
+ };
1171
+ var workspaceMapOf = ({ root, cwd }) => {
1172
+ const projectRoot = projectRootOf(root, cwd);
1173
+ const found = areaDirsOf(projectRoot, root);
1174
+ if (found.length < 2) {
1175
+ return void 0;
1176
+ }
1177
+ const cwdRel = posix(relative(projectRoot, cwd));
1178
+ const isHere = (name) => cwdRel === name || cwdRel.startsWith(`${name}/`);
1179
+ const asArea = (name, dir, packages, children) => {
1180
+ const { files, kinds } = measure(dir, root);
1181
+ return { name, files, kinds, purpose: purposeOf(dir), here: isHere(name), packages, children, childrenOmitted: 0 };
1182
+ };
1183
+ const expand = (parent, entries) => {
1184
+ const ranked2 = entries.map((entry) => asArea(`${parent}/${entry.name}`, entry.dir, packagesIn(entry.dir, root).length, [])).toSorted((left, right) => right.files - left.files || left.name.localeCompare(right.name));
1185
+ return { children: ranked2.slice(0, MAX_EXPANDED), childrenOmitted: Math.max(0, ranked2.length - MAX_EXPANDED) };
1186
+ };
1187
+ const base = found.map((area) => ({ ...area, measured: asArea(area.name, area.dir, area.packages.length, []) }));
1188
+ const total = base.reduce((sum, entry) => sum + entry.measured.files, 0);
1189
+ const biggest = base.toSorted((left, right) => right.measured.files - left.measured.files)[0];
1190
+ const dominant = cwdRel === "" && biggest !== void 0 && biggest.measured.files >= total * DOMINANT_SHARE ? biggest.name : void 0;
1191
+ const measured = base.map(({ name, dir, packages, measured: area }) => {
1192
+ if (isHere(name)) {
1193
+ return { ...area, ...expand(name, packages) };
1194
+ }
1195
+ return name === dominant ? { ...area, ...expand(name, areaDirsOf(dir, root)) } : area;
1196
+ });
1197
+ const ranked = measured.toSorted((left, right) => right.files - left.files || left.name.localeCompare(right.name));
1198
+ const kept = ranked.slice(0, MAX_AREAS);
1199
+ const here = ranked.slice(MAX_AREAS).filter((area) => area.here);
1200
+ const areas = [...kept, ...here];
1201
+ return {
1202
+ project: posix(relative(root, projectRoot)),
1203
+ cwd: posix(relative(root, cwd)),
1204
+ areas,
1205
+ omitted: ranked.length - areas.length,
1206
+ // Only meaningful when the project isn't the whole workspace: names what else is there, nothing more.
1207
+ siblings: projectRoot === root ? [] : childDirs(root, root).filter((name) => name !== basename(projectRoot))
1208
+ };
1209
+ };
1210
+ var sizeOf = (area) => `${area.files} file${area.files === 1 ? "" : "s"}${area.kinds.length > 0 ? ` \xB7 ${area.kinds.join(", ")}` : ""}${area.packages > 0 ? ` \xB7 ${area.packages} packages` : ""}`;
1211
+ var areaLine = (area, width, indent) => `${indent}${area.name.padEnd(width - indent.length)} ${sizeOf(area)}${area.here && area.children.length === 0 ? " \u2190 you are here" : ""}`;
1212
+ var areaBlock = (area, width, silent) => [
1213
+ areaLine(area, width, " "),
1214
+ ...area.purpose === "" || silent.has(area.name) ? [] : [` ${" ".repeat(width - 2)} ${area.purpose}`],
1215
+ ...area.children.flatMap((child) => [
1216
+ areaLine(child, width, " "),
1217
+ ...child.purpose === "" || silent.has(child.name) ? [] : [` ${" ".repeat(width - 6)} ${child.purpose}`]
1218
+ ]),
1219
+ // What opening this area left out; unsaid, it reads as if that were the whole list.
1220
+ ...area.childrenOmitted > 0 ? [` \u2026 and ${area.childrenOmitted} more in ${area.name}`] : []
1221
+ ];
1222
+ var render = (map, exactPaths) => {
1223
+ const project = map.project === "" ? "the workspace" : `\`${map.project}\``;
1224
+ const all = map.areas.flatMap((area) => [area, ...area.children]);
1225
+ const width = Math.min(
1226
+ Math.max(...map.areas.flatMap((area) => [area.name.length + 2, ...area.children.map((child) => child.name.length + 6)])) + 2,
1227
+ 34
1228
+ );
1229
+ const head = [
1230
+ WORKSPACE_MAP_NOTE_HEADER,
1231
+ "",
1232
+ `This is current filesystem context. It maps project areas, not file locations; use ${exactPaths} for exact paths.`,
1233
+ "Do not `ls` or `tree` the workspace root to orient yourself \u2014 the map above is that orientation.",
1234
+ "",
1235
+ map.cwd === map.project ? `You are at the top of ${project}.` : `You are here: \`${map.cwd}\``,
1236
+ "",
1237
+ `${project}, ${map.areas.length} area${map.areas.length === 1 ? "" : "s"}${map.omitted > 0 ? `, plus ${map.omitted} smaller ones not listed` : ""}`
1238
+ ];
1239
+ const tail = map.siblings.length > 0 ? ["", `Also under the workspace root: ${map.siblings.map((name) => `${name}/`).join(", ")}`] : [];
1240
+ const byFilesAsc = all.toSorted((left, right) => left.files - right.files).map((area) => area.name);
1241
+ for (let muted = 0; muted <= byFilesAsc.length; muted += 1) {
1242
+ const silent2 = new Set(byFilesAsc.slice(0, muted));
1243
+ const note = [...head, ...map.areas.flatMap((area) => areaBlock(area, width, silent2)), ...tail].join("\n");
1244
+ if (note.length <= MAX_NOTE_CHARS) {
1245
+ return note;
1246
+ }
1247
+ }
1248
+ const silent = new Set(byFilesAsc);
1249
+ const lines = [];
1250
+ let used = [...head, ...tail].join("\n").length;
1251
+ let dropped = 0;
1252
+ for (const area of map.areas) {
1253
+ const block = areaBlock(area, width, silent);
1254
+ const cost = block.reduce((sum, line) => sum + line.length + 1, 0);
1255
+ if (used + cost > MAX_NOTE_CHARS) {
1256
+ dropped += 1;
1257
+ continue;
1258
+ }
1259
+ used += cost;
1260
+ lines.push(...block);
1261
+ }
1262
+ const total = map.omitted + dropped;
1263
+ return [...head, ...lines, ...total > 0 ? [` \u2026 and ${total} more`] : [], ...tail].join("\n");
1264
+ };
1265
+ var TTL_MS = 6e4;
1266
+ var cache = /* @__PURE__ */ new Map();
1267
+ var workspaceMapNote = (input) => {
1268
+ const exactPaths = input.exactPaths ?? "`iq files` or Read";
1269
+ const key = `${input.root}\0${input.cwd}\0${exactPaths}`;
1270
+ const hit = cache.get(key);
1271
+ if (hit !== void 0 && Date.now() - hit.at < TTL_MS) {
1272
+ return hit.note;
1273
+ }
1274
+ let note;
1275
+ try {
1276
+ const map = workspaceMapOf(input);
1277
+ note = map === void 0 ? void 0 : render(map, exactPaths);
1278
+ } catch {
1279
+ note = void 0;
1280
+ }
1281
+ cache.set(key, { at: Date.now(), note });
1282
+ return note;
1283
+ };
1284
+
1285
+ // src/features.ts
1286
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "node:fs";
1287
+ import { join as join3 } from "node:path";
1288
+
1289
+ // src/runtime.ts
1290
+ import { spawn } from "node:child_process";
1291
+ import { accessSync, closeSync, constants, mkdirSync, openSync, readFileSync as readFileSync3, statSync as statSync3, writeFileSync } from "node:fs";
1292
+ import { delimiter, dirname as dirname2, join as join2 } from "node:path";
1293
+ var pluginRoot = (env = process.env) => env["CLAUDE_PLUGIN_ROOT"] ?? dirname2(import.meta.dirname);
1294
+ var isMissing = (error) => {
1295
+ const code = typeof error === "object" && error !== null ? error.code : void 0;
1296
+ return code === "ENOENT" || code === "ENOTDIR";
1297
+ };
1298
+ var pluginFile = (parts, env = process.env) => {
1299
+ try {
1300
+ return readFileSync3(join2(pluginRoot(env), ...parts), "utf8");
1301
+ } catch (error) {
1302
+ if (isMissing(error)) {
1303
+ return void 0;
1304
+ }
1305
+ throw error;
1306
+ }
1307
+ };
1308
+ var onPath = (name, env = process.env) => {
1309
+ const extensions = process.platform === "win32" ? (env["PATHEXT"] ?? ".EXE;.CMD;.BAT").split(";") : [""];
1310
+ for (const dir of (env["PATH"] ?? "").split(delimiter)) {
1311
+ for (const extension of extensions) {
1312
+ try {
1313
+ accessSync(join2(dir, `${name}${extension}`), constants.X_OK);
1314
+ return true;
1315
+ } catch {
1316
+ }
1317
+ }
1318
+ }
1319
+ return false;
1320
+ };
1321
+ var startDetached = (command, args, options) => {
1322
+ mkdirSync(dirname2(options.log), { recursive: true });
1323
+ const out = openSync(options.log, "w");
1324
+ try {
1325
+ const child = spawn(command, args, { cwd: options.cwd, detached: true, stdio: ["ignore", out, out], env: { ...options.env ?? process.env } });
1326
+ child.on("error", () => void 0);
1327
+ child.unref();
1328
+ } finally {
1329
+ closeSync(out);
1330
+ }
1331
+ };
1332
+ var claimIfDue = (stamp, everyMs, now = Date.now()) => {
1333
+ try {
1334
+ if (now - statSync3(stamp).mtimeMs < everyMs) {
1335
+ return false;
1336
+ }
1337
+ } catch {
1338
+ }
1339
+ try {
1340
+ mkdirSync(dirname2(stamp), { recursive: true });
1341
+ writeFileSync(stamp, `${now}
1342
+ `);
1343
+ return true;
1344
+ } catch (error) {
1345
+ process.stderr.write(`intentic: ${stamp} cannot be written (${error instanceof Error ? error.message : String(error)}), so what it paces is skipped
1346
+ `);
1347
+ return false;
1348
+ }
1349
+ };
1350
+ var projectSlug = (project) => project.replace(/[^a-zA-Z0-9]/g, "-");
1351
+
1352
+ // src/features.ts
1353
+ var OPTIONS = {
1354
+ output_cleaners: {
1355
+ type: "boolean",
1356
+ title: "Trim Bash output",
1357
+ description: "Clean what a successful command printed before Claude reads it (progress bars, install chatter, repeated lines, the middle of huge logs), keep the full text retrievable with `retrieve-output`, and ledger what each cleaner saved.",
1358
+ default: true
1359
+ },
1360
+ cleaners: {
1361
+ type: "string",
1362
+ title: "Cleaners",
1363
+ description: "Which cleaners run, as the sandbox spells it: empty for all, `-cap,-wide` to switch some off, `git,pnpm` to allow only those. `/intentic:stats` lists them by what they saved.",
1364
+ default: ""
1365
+ },
1366
+ output_holdout: {
1367
+ type: "number",
1368
+ title: "Untrimmed share",
1369
+ description: "Share of commands left untrimmed, so the saving can be measured against a real comparison and not only computed. 0 turns the comparison off; the exact per-command saving is reported either way.",
1370
+ default: 0,
1371
+ min: 0,
1372
+ max: 0.5
1373
+ },
1374
+ project_map: {
1375
+ type: "boolean",
1376
+ title: "Project map",
1377
+ description: "Open each session with a map of the project it starts in: its areas, what each is for, and where Claude is standing. Worked out from the tree every time, never stored, so it cannot go stale.",
1378
+ default: true
1379
+ },
1380
+ field_notes: {
1381
+ type: "boolean",
1382
+ title: "Field notes",
1383
+ description: "Open each session with this project's field notes: the traps past sessions hit and the commands that really verify. Written by `/intentic:field-notes` from your own sessions here; nothing is sent until you run it once.",
1384
+ default: true
1385
+ },
1386
+ iq: {
1387
+ type: "boolean",
1388
+ title: "iq search",
1389
+ description: "Teach Claude the `iq` code search CLI and recall past sessions on a matching prompt. Needs `npm i -g @intentic/iq`; without it this switch does nothing and says so once.",
1390
+ default: true
1391
+ },
1392
+ fileq: {
1393
+ type: "boolean",
1394
+ title: "fileq",
1395
+ description: "Let Claude read documents, PDFs, spreadsheets, slides, notebooks, images, audio and archives as markdown with the bundled `fileq` CLI. Off makes the command refuse; its one-line skill description stays listed, since a plugin cannot hide its own skills.",
1396
+ default: true
1397
+ },
1398
+ shadows: {
1399
+ type: "boolean",
1400
+ title: "Document shadows",
1401
+ description: "Keep a markdown rendering of every document in the project up to date in the background (a sweep at session start and every ten minutes, and each binary file Claude writes), so a read finds one ready. Costs background CPU on a document-heavy project.",
1402
+ default: false
1403
+ },
1404
+ holdout: {
1405
+ type: "number",
1406
+ title: "Measured share",
1407
+ description: "Share of sessions opened without the map, the field notes and the iq teaching, so `/intentic:stats` can show what each changed. 0 sends them to every session and measures nothing.",
1408
+ default: 0.1,
1409
+ min: 0,
1410
+ max: 0.5
1411
+ }
1412
+ };
1413
+ var asBoolean = (raw, fallback) => {
1414
+ const value = raw?.trim().toLowerCase();
1415
+ if (value === "true" || value === "1" || value === "yes" || value === "on") {
1416
+ return true;
1417
+ }
1418
+ if (value === "false" || value === "0" || value === "no" || value === "off") {
1419
+ return false;
1420
+ }
1421
+ return fallback;
1422
+ };
1423
+ var asShare = (raw, option) => {
1424
+ const value = raw === void 0 || raw.trim() === "" ? Number.NaN : Number(raw);
1425
+ return Number.isFinite(value) ? Math.min(option.max, Math.max(option.min, value)) : option.default;
1426
+ };
1427
+ var optionEnvName = (key) => `CLAUDE_PLUGIN_OPTION_${key.toUpperCase()}`;
1428
+ var readOptions = (env = process.env) => {
1429
+ const entries = Object.keys(OPTIONS).map((key) => {
1430
+ const option = OPTIONS[key];
1431
+ const raw = env[optionEnvName(key)];
1432
+ if (option.type === "boolean") {
1433
+ return [key, asBoolean(raw, option.default)];
1434
+ }
1435
+ if (option.type === "number") {
1436
+ return [key, asShare(raw, option)];
1437
+ }
1438
+ return [key, raw ?? option.default];
1439
+ });
1440
+ return Object.fromEntries(entries);
1441
+ };
1442
+ var optionsFile = (data) => join3(data, "options.json");
1443
+ var saveOptions = (data, options) => {
1444
+ mkdirSync2(data, { recursive: true });
1445
+ writeFileSync2(optionsFile(data), `${JSON.stringify(options)}
1446
+ `);
1447
+ };
1448
+
1449
+ // src/hook-io.ts
1450
+ import { homedir } from "node:os";
1451
+ import { join as join4 } from "node:path";
1452
+ var readStdin = async () => {
1453
+ const chunks = [];
1454
+ for await (const chunk of process.stdin) {
1455
+ chunks.push(chunk);
1456
+ }
1457
+ return Buffer.concat(chunks).toString("utf8");
1458
+ };
1459
+ var parseHookInput = (text) => {
1460
+ try {
1461
+ const value = JSON.parse(text);
1462
+ return typeof value === "object" && value !== null ? value : void 0;
1463
+ } catch {
1464
+ return void 0;
1465
+ }
1466
+ };
1467
+ var runHook = async (handle) => {
1468
+ try {
1469
+ const raw = await readStdin();
1470
+ const input = parseHookInput(raw);
1471
+ if (input === void 0) {
1472
+ return;
1473
+ }
1474
+ const answer = await handle(input, raw);
1475
+ if (typeof answer === "string") {
1476
+ process.stdout.write(answer);
1477
+ } else if (answer !== void 0) {
1478
+ process.stdout.write(`${JSON.stringify(answer)}
1479
+ `);
1480
+ }
1481
+ } catch (error) {
1482
+ process.stderr.write(`intentic: ${error instanceof Error ? error.message : String(error)}
1483
+ `);
1484
+ }
1485
+ };
1486
+ var dataDir = (env = process.env) => env["CLAUDE_PLUGIN_DATA"] ?? join4(env["CLAUDE_CONFIG_DIR"] ?? join4(homedir(), ".claude"), "plugins", "data", "intentic-intentic");
1487
+ var projectDir = (input, env = process.env) => env["CLAUDE_PROJECT_DIR"] ?? input.cwd ?? process.cwd();
1488
+ var fieldNotesFile = (project) => join4(project, ".claude", "intentic", "field-notes.toon");
1489
+
1490
+ // src/sessions.ts
1491
+ import { appendFileSync, mkdirSync as mkdirSync3, readFileSync as readFileSync5 } from "node:fs";
1492
+ import { dirname as dirname3, join as join5 } from "node:path";
1493
+
1494
+ // ../agent-context/src/experiments.ts
1495
+ import { createHash as createHash2 } from "node:crypto";
1496
+ var experimentArm = (experiment, id, holdout) => {
1497
+ if (id === void 0) {
1498
+ return Math.random() >= holdout;
1499
+ }
1500
+ const bucket = createHash2("sha256").update(`${experiment}:${id}`).digest().readUInt32BE(0) / 4294967296;
1501
+ return bucket >= holdout;
1502
+ };
1503
+
1504
+ // src/sessions.ts
1505
+ var SALTS = { map: "workspace-map", notes: "field-notes", iq: "iq-search" };
1506
+ var MECHANISM_ON = {
1507
+ map: (options) => options.project_map,
1508
+ notes: (options) => options.field_notes,
1509
+ iq: (options) => options.iq
1510
+ };
1511
+ var armsOf = (options, session) => {
1512
+ const arms = {};
1513
+ for (const mechanism of Object.keys(SALTS)) {
1514
+ if (MECHANISM_ON[mechanism](options) && options.holdout > 0 && session !== void 0) {
1515
+ arms[mechanism] = experimentArm(SALTS[mechanism], session, options.holdout);
1516
+ }
1517
+ }
1518
+ return arms;
1519
+ };
1520
+ var sends = (options, arms, mechanism) => MECHANISM_ON[mechanism](options) && arms[mechanism] !== false;
1521
+ var measuredArms = (arms, offered) => Object.fromEntries(Object.entries(arms).filter(([mechanism]) => offered[mechanism] === true));
1522
+ var sessionsFile = (data) => join5(data, "sessions.jsonl");
1523
+ var recordSession = (data, row) => {
1524
+ const file = sessionsFile(data);
1525
+ mkdirSync3(dirname3(file), { recursive: true });
1526
+ appendFileSync(file, `${JSON.stringify(row)}
1527
+ `);
1528
+ };
1529
+
1530
+ // src/shadows.ts
1531
+ import { relative as relative2, isAbsolute, join as join6 } from "node:path";
1532
+ var SWEEP_EVERY_MS = 10 * 6e4;
1533
+ var fileq = (env) => join6(pluginRoot(env), "dist", "fileq.mjs");
1534
+ var logOf = (data, project, what) => join6(data, "shadows", `${projectSlug(project)}.${what}.log`);
1535
+ var fileqEnv = (env, project) => ({ ...env, WORKSPACE_ROOT: project });
1536
+ var sweepIfDue = (data, project, env = process.env, now = Date.now()) => {
1537
+ if (!claimIfDue(join6(data, "shadows", `${projectSlug(project)}.stamp`), SWEEP_EVERY_MS, now)) {
1538
+ return false;
1539
+ }
1540
+ startDetached(process.execPath, [fileq(env), "sweep", "--json"], { cwd: project, log: logOf(data, project, "sweep"), env: fileqEnv(env, project) });
1541
+ return true;
1542
+ };
1543
+
1544
+ // src/session-start.ts
1545
+ var NOTES_BUDGET = 4e3;
1546
+ var NOTICE_EVERY_MS = 24 * 60 * 6e4;
1547
+ var TOLD_ON = /* @__PURE__ */ new Set(["startup", "clear", "compact"]);
1548
+ var COUNTED_ON = /* @__PURE__ */ new Set(["startup", "clear"]);
1549
+ var compose = (options, input, project, arms, data, env) => {
1550
+ const context = [];
1551
+ const notices = [];
1552
+ const notice = (id, text) => {
1553
+ if (claimIfDue(join7(data, "notices", `${id}.stamp`), NOTICE_EVERY_MS)) {
1554
+ notices.push(text);
1555
+ }
1556
+ };
1557
+ const iq = options.iq && onPath("iq", env);
1558
+ const sent = {};
1559
+ const offered = {};
1560
+ let notesRevision;
1561
+ if (options.project_map) {
1562
+ const note = workspaceMapNote({ root: project, cwd: input.cwd ?? project, exactPaths: iq ? "`iq files` or Read" : "Glob or Read" });
1563
+ offered.map = note !== void 0;
1564
+ if (note !== void 0 && sends(options, arms, "map")) {
1565
+ context.push(note);
1566
+ sent.map = note.length;
1567
+ }
1568
+ }
1569
+ if (options.field_notes) {
1570
+ const brief = fieldNotes({
1571
+ file: fieldNotesFile(project),
1572
+ title: "Field notes for this project",
1573
+ budget: NOTES_BUDGET,
1574
+ onUnreadable: (why) => notice(`notes-${projectSlug(project)}`, `intentic: this project's field notes were not sent: ${why}. Run /intentic:field-notes to rewrite them.`)
1575
+ });
1576
+ notesRevision = brief?.revision;
1577
+ offered.notes = brief !== void 0;
1578
+ if (brief !== void 0 && sends(options, arms, "notes")) {
1579
+ context.push(brief.text);
1580
+ sent.notes = brief.chars;
1581
+ }
1582
+ }
1583
+ if (options.iq) {
1584
+ if (iq) {
1585
+ const nudge = pluginFile(["generated", "iq-nudge.txt"], env);
1586
+ offered.iq = nudge !== void 0;
1587
+ if (nudge !== void 0 && sends(options, arms, "iq")) {
1588
+ context.push(`## iq workspace search
1589
+
1590
+ ${nudge.trim()}`);
1591
+ sent.iq = true;
1592
+ }
1593
+ startDetached("iq", ["sessions", "ingest"], { cwd: project, log: join7(data, "iq", `${projectSlug(project)}.ingest.log`), env });
1594
+ } else {
1595
+ notice("iq-missing", "intentic: iq search is on but the `iq` CLI is not installed (`npm i -g @intentic/iq`), so nothing was taught.");
1596
+ }
1597
+ }
1598
+ return { context, row: { arms: measuredArms(arms, offered), sent, ...notesRevision === void 0 ? {} : { notesRevision } }, notices };
1599
+ };
1600
+ var exportEnv = (options, project, env) => {
1601
+ const file = env["CLAUDE_ENV_FILE"];
1602
+ if (file === void 0 || file === "") {
1603
+ return;
1604
+ }
1605
+ const quoted = `'${project.replaceAll("'", `'\\''`)}'`;
1606
+ appendFileSync2(file, `export INTENTIC_PROJECT_DIR=${quoted}
1607
+ export INTENTIC_FILEQ=${options.fileq ? "1" : "0"}
1608
+ `);
1609
+ };
1610
+ var record = (what, write) => {
1611
+ try {
1612
+ write();
1613
+ } catch (error) {
1614
+ process.stderr.write(`intentic: ${what} not recorded: ${error instanceof Error ? error.message : String(error)}
1615
+ `);
1616
+ }
1617
+ };
1618
+ var sessionStart = (input, env = process.env) => {
1619
+ const options = readOptions(env);
1620
+ const data = dataDir(env);
1621
+ const project = projectDir(input, env);
1622
+ const source = input.source ?? "startup";
1623
+ record("the switches", () => saveOptions(data, options));
1624
+ exportEnv(options, project, env);
1625
+ if (options.shadows && existsSync(project)) {
1626
+ sweepIfDue(data, project, env);
1627
+ }
1628
+ if (!TOLD_ON.has(source)) {
1629
+ return void 0;
1630
+ }
1631
+ const { context, row, notices } = compose(options, input, project, armsOf(options, input.session_id), data, env);
1632
+ const session = input.session_id;
1633
+ if (COUNTED_ON.has(source) && session !== void 0) {
1634
+ record(
1635
+ "the session",
1636
+ () => recordSession(data, {
1637
+ ts: Date.now(),
1638
+ session,
1639
+ project,
1640
+ ...input.transcript_path === void 0 ? {} : { transcript: input.transcript_path },
1641
+ ...row
1642
+ })
1643
+ );
1644
+ }
1645
+ if (context.length === 0 && notices.length === 0) {
1646
+ return void 0;
1647
+ }
1648
+ return {
1649
+ ...notices.length === 0 ? {} : { systemMessage: notices.join("\n") },
1650
+ hookSpecificOutput: { hookEventName: "SessionStart", ...context.length === 0 ? {} : { additionalContext: context.join("\n\n") } }
1651
+ };
1652
+ };
1653
+ if (process.argv[1]?.endsWith("session-start.mjs")) {
1654
+ await runHook((input) => sessionStart(input));
1655
+ }
1656
+ export {
1657
+ sessionStart
1658
+ };