@intentic/claude-plugin 1.326.0 → 1.327.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/.claude-plugin/plugin.json +1 -1
- package/dist/fileq.mjs +71332 -71203
- package/dist/notes-evidence.mjs +61 -13
- package/dist/retrieve-output.mjs +9 -4
- package/dist/session-start.mjs +264 -97
- package/dist/stats.mjs +61 -16
- package/generated/skills/field-notes/SKILL.md +1 -1
- package/generated/skills/iq/SKILL.md +9 -3
- package/package.json +4 -4
package/dist/session-start.mjs
CHANGED
|
@@ -29,9 +29,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
29
29
|
mod
|
|
30
30
|
));
|
|
31
31
|
|
|
32
|
-
// ../../node_modules/.pnpm/ignore@7.0.
|
|
32
|
+
// ../../node_modules/.pnpm/ignore@7.0.12/node_modules/ignore/index.js
|
|
33
33
|
var require_ignore = __commonJS({
|
|
34
|
-
"../../node_modules/.pnpm/ignore@7.0.
|
|
34
|
+
"../../node_modules/.pnpm/ignore@7.0.12/node_modules/ignore/index.js"(exports, module) {
|
|
35
35
|
function makeArray(subject) {
|
|
36
36
|
return Array.isArray(subject) ? subject : [subject];
|
|
37
37
|
}
|
|
@@ -40,7 +40,7 @@ var require_ignore = __commonJS({
|
|
|
40
40
|
var SPACE = " ";
|
|
41
41
|
var ESCAPE = "\\";
|
|
42
42
|
var REGEX_LITERAL_SPECIAL = /[.*+?()[\]{}^$|\\/]/;
|
|
43
|
-
var
|
|
43
|
+
var BOM = "\uFEFF";
|
|
44
44
|
var REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/;
|
|
45
45
|
var REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/;
|
|
46
46
|
var REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/;
|
|
@@ -165,6 +165,7 @@ var require_ignore = __commonJS({
|
|
|
165
165
|
"g"
|
|
166
166
|
);
|
|
167
167
|
var TRAILING_WILDCARD = "\uE000";
|
|
168
|
+
var TRAILING_DOUBLESTAR = "\uE001";
|
|
168
169
|
var extractBrackets = (pattern) => {
|
|
169
170
|
const sources = [];
|
|
170
171
|
const hold = (source) => `${PLACEHOLDER}${sources.push(source) - 1}${PLACEHOLDER}`;
|
|
@@ -175,7 +176,9 @@ var require_ignore = __commonJS({
|
|
|
175
176
|
const char = pattern[index];
|
|
176
177
|
if (char === ESCAPE) {
|
|
177
178
|
const escaped = pattern[index + 1];
|
|
178
|
-
if (escaped ===
|
|
179
|
+
if (escaped === UNDEFINED || escaped === SLASH && index + 2 === length) {
|
|
180
|
+
out += hold(NEVER_MATCH);
|
|
181
|
+
} else if (escaped === "*" || escaped === "[" || escaped === SPACE || escaped === ESCAPE) {
|
|
179
182
|
out += pattern.slice(index, index + 2);
|
|
180
183
|
} else {
|
|
181
184
|
out += hold(
|
|
@@ -208,35 +211,6 @@ var require_ignore = __commonJS({
|
|
|
208
211
|
var DIRECT = null;
|
|
209
212
|
var REGEX_INNER_SLASH = /\/(?!$)/;
|
|
210
213
|
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
214
|
// Replace (\ ) with ' '
|
|
241
215
|
// Only a space: an escaped tab or other whitespace is already a literal by
|
|
242
216
|
// the time it reaches here, and a bare tab must be left as one, not turned
|
|
@@ -245,11 +219,12 @@ var require_ignore = __commonJS({
|
|
|
245
219
|
// (\\ ) -> '\\ '
|
|
246
220
|
// (\\\ ) -> '\\ '
|
|
247
221
|
[
|
|
248
|
-
|
|
249
|
-
(
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
222
|
+
// A run of backslashes is taken whole, from its first one, so no match
|
|
223
|
+
// ever starts again inside it -- `(\\+?) ` did, which made a long run
|
|
224
|
+
// quadratic.
|
|
225
|
+
/(\\+)( ?)/g,
|
|
226
|
+
(_, run, space) => space ? run.slice(0, run.length - run.length % 2) + SPACE : run,
|
|
227
|
+
ESCAPE + SPACE
|
|
253
228
|
],
|
|
254
229
|
// Escape metacharacters
|
|
255
230
|
// which is written down by users but means special for regular expressions.
|
|
@@ -325,7 +300,7 @@ var require_ignore = __commonJS({
|
|
|
325
300
|
// Zero, one or several directories
|
|
326
301
|
// should not use '*', or it will be replaced by the next replacer
|
|
327
302
|
// Check if it is not the last `'/**'`
|
|
328
|
-
(_, index, str) => index + 6 < str.length ? str.slice(index + 6) === "\\/" ? "(?:\\/[^\\/]+)+" : "(?:\\/[^\\/]+)*" :
|
|
303
|
+
(_, index, str) => index + 6 < str.length ? str.slice(index + 6) === "\\/" ? "(?:\\/[^\\/]+)+" : "(?:\\/[^\\/]+)*" : `\\/${TRAILING_DOUBLESTAR}`,
|
|
329
304
|
"*"
|
|
330
305
|
],
|
|
331
306
|
// normal intermediate wildcards
|
|
@@ -403,7 +378,7 @@ var require_ignore = __commonJS({
|
|
|
403
378
|
// 'js' will match 'a.js' and 'a.js/'
|
|
404
379
|
(source) => {
|
|
405
380
|
const last = source[source.length - 1];
|
|
406
|
-
if (!last || last === TRAILING_WILDCARD) {
|
|
381
|
+
if (!last || last === TRAILING_WILDCARD || last === TRAILING_DOUBLESTAR) {
|
|
407
382
|
return source;
|
|
408
383
|
}
|
|
409
384
|
return last === SLASH ? `${source}$` : `${source}(?=$|\\/$)`;
|
|
@@ -414,16 +389,12 @@ var require_ignore = __commonJS({
|
|
|
414
389
|
var MODE_IGNORE = "regex";
|
|
415
390
|
var MODE_CHECK_IGNORE = "checkRegex";
|
|
416
391
|
var UNDERSCORE = "_";
|
|
417
|
-
var
|
|
418
|
-
[
|
|
419
|
-
|
|
420
|
-
return `${prefix}(?=$|\\/$)`;
|
|
421
|
-
},
|
|
422
|
-
[MODE_CHECK_IGNORE](_, p1) {
|
|
423
|
-
const prefix = p1 ? `${p1}[^/]*` : "[^/]*";
|
|
424
|
-
return `${prefix}(?=$|\\/$)`;
|
|
425
|
-
}
|
|
392
|
+
var replaceTrailingWildcard = (_, p1) => {
|
|
393
|
+
const prefix = p1 ? `${p1}[^/]+` : "[^/]*";
|
|
394
|
+
return `${prefix}(?=$|\\/$)`;
|
|
426
395
|
};
|
|
396
|
+
var REGEX_REPLACE_TRAILING_DOUBLESTAR = /\uE001$/;
|
|
397
|
+
var replaceTrailingDoublestar = () => ".+(?=$|\\/$)";
|
|
427
398
|
var WILDCARD = "[^\\/]*";
|
|
428
399
|
var separatorAfter = (run, at) => {
|
|
429
400
|
let separator = EMPTY;
|
|
@@ -539,6 +510,14 @@ var require_ignore = __commonJS({
|
|
|
539
510
|
(match, index) => sources[index]
|
|
540
511
|
) : replaced;
|
|
541
512
|
};
|
|
513
|
+
var checkSourceOf = (body, prefix) => {
|
|
514
|
+
if (body[body.length - 1] === SLASH) {
|
|
515
|
+
prefix = makeRegexPrefix(body.slice(0, -1));
|
|
516
|
+
}
|
|
517
|
+
const head = prefix.slice(0, -1);
|
|
518
|
+
const last = prefix[prefix.length - 1];
|
|
519
|
+
return last === TRAILING_WILDCARD ? `${head}$` : last === TRAILING_DOUBLESTAR ? `${head}.*$` : NEVER_MATCH;
|
|
520
|
+
};
|
|
542
521
|
var matchesBasename = (body) => {
|
|
543
522
|
const index = body.indexOf(SLASH);
|
|
544
523
|
return index < 0 || index === body.length - 1;
|
|
@@ -565,7 +544,7 @@ var require_ignore = __commonJS({
|
|
|
565
544
|
return cut < 0 ? EMPTY : path.slice(0, cut + 1);
|
|
566
545
|
};
|
|
567
546
|
var isString = (subject) => typeof subject === "string";
|
|
568
|
-
var checkPattern = (pattern) => pattern && isString(pattern) && !
|
|
547
|
+
var checkPattern = (pattern) => pattern && isString(pattern) && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern);
|
|
569
548
|
var splitPattern = (pattern) => pattern.split(REGEX_SPLITALL_CRLF).filter(Boolean);
|
|
570
549
|
var IgnoreRule = class {
|
|
571
550
|
constructor(pattern, mark, body, ignoreCase, negative, prefix) {
|
|
@@ -599,24 +578,51 @@ var require_ignore = __commonJS({
|
|
|
599
578
|
return this._make(MODE_CHECK_IGNORE, key);
|
|
600
579
|
}
|
|
601
580
|
_make(mode, key) {
|
|
602
|
-
const str = pinWildcards(
|
|
603
|
-
REGEX_REPLACE_TRAILING_WILDCARD,
|
|
604
|
-
|
|
605
|
-
TRAILING_WILD_CARD_REPLACERS[mode]
|
|
606
|
-
));
|
|
581
|
+
const str = pinWildcards(
|
|
582
|
+
mode === MODE_IGNORE ? this.regexPrefix.replace(REGEX_REPLACE_TRAILING_WILDCARD, replaceTrailingWildcard).replace(REGEX_REPLACE_TRAILING_DOUBLESTAR, replaceTrailingDoublestar) : checkSourceOf(this.body, this.regexPrefix)
|
|
583
|
+
);
|
|
607
584
|
const regex = this.ignoreCase ? new RegExp(str, "i") : new RegExp(str);
|
|
608
585
|
return define(this, key, regex);
|
|
609
586
|
}
|
|
610
587
|
};
|
|
588
|
+
var isLineEnd = (char) => char === "\r" || char === "\n";
|
|
589
|
+
var trimEnd = (body) => {
|
|
590
|
+
let end = body.length;
|
|
591
|
+
while (end && isLineEnd(body[end - 1])) {
|
|
592
|
+
end--;
|
|
593
|
+
}
|
|
594
|
+
const lineEnd = end;
|
|
595
|
+
while (end && body[end - 1] === SPACE) {
|
|
596
|
+
end--;
|
|
597
|
+
}
|
|
598
|
+
if (end === lineEnd) {
|
|
599
|
+
return body.slice(0, end);
|
|
600
|
+
}
|
|
601
|
+
let backslashes = 0;
|
|
602
|
+
while (backslashes < end && body[end - backslashes - 1] === ESCAPE) {
|
|
603
|
+
backslashes++;
|
|
604
|
+
}
|
|
605
|
+
return backslashes % 2 ? body.slice(0, end - 1) + SPACE : body.slice(0, end);
|
|
606
|
+
};
|
|
611
607
|
var createRule = ({
|
|
612
608
|
pattern,
|
|
613
609
|
mark
|
|
614
610
|
}, ignoreCase) => {
|
|
611
|
+
let body = pattern[0] === BOM ? pattern.slice(1) : pattern;
|
|
612
|
+
if (body[0] === "#") {
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
615
|
let negative = false;
|
|
616
|
-
|
|
617
|
-
if (body.indexOf("!") === 0) {
|
|
616
|
+
if (body[0] === "!") {
|
|
618
617
|
negative = true;
|
|
619
|
-
body = body.
|
|
618
|
+
body = body.slice(1);
|
|
619
|
+
}
|
|
620
|
+
const last = body[body.length - 1];
|
|
621
|
+
if (last === SPACE || last === "\r" || last === "\n") {
|
|
622
|
+
body = trimEnd(body);
|
|
623
|
+
}
|
|
624
|
+
if (!body) {
|
|
625
|
+
return;
|
|
620
626
|
}
|
|
621
627
|
body = body.replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, "!").replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, "#");
|
|
622
628
|
const regexPrefix = makeRegexPrefix(body);
|
|
@@ -647,8 +653,8 @@ var require_ignore = __commonJS({
|
|
|
647
653
|
pattern
|
|
648
654
|
};
|
|
649
655
|
}
|
|
650
|
-
|
|
651
|
-
|
|
656
|
+
const rule = checkPattern(pattern.pattern) && createRule(pattern, this._ignoreCase);
|
|
657
|
+
if (rule) {
|
|
652
658
|
this._added = true;
|
|
653
659
|
this._rules.push(rule);
|
|
654
660
|
if (matchesBasename(rule.body)) {
|
|
@@ -662,8 +668,39 @@ var require_ignore = __commonJS({
|
|
|
662
668
|
makeArray(
|
|
663
669
|
isString(pattern) ? splitPattern(pattern) : pattern
|
|
664
670
|
).forEach(this._add, this);
|
|
671
|
+
if (this._added) {
|
|
672
|
+
this._literalRules = UNDEFINED;
|
|
673
|
+
}
|
|
665
674
|
return this._added;
|
|
666
675
|
}
|
|
676
|
+
// Match the literal 'abc/' for `checkIgnore`, last rule wins. Only a rule
|
|
677
|
+
// ending in a wildcard can match it (see `checkSourceOf`), so the rest
|
|
678
|
+
// are left out once, rather than tested or compiled for every path.
|
|
679
|
+
testLiteral(path) {
|
|
680
|
+
const rules = this._literalRules || (this._literalRules = this._rules.filter(
|
|
681
|
+
({ body }) => body[body.length - (body[body.length - 1] === SLASH ? 2 : 1)] === "*"
|
|
682
|
+
));
|
|
683
|
+
let ignored = false;
|
|
684
|
+
let unignored = false;
|
|
685
|
+
let matchedRule;
|
|
686
|
+
for (let index = rules.length - 1; index >= 0; index--) {
|
|
687
|
+
const rule = rules[index];
|
|
688
|
+
if (rule.checkRegex.test(path)) {
|
|
689
|
+
ignored = !rule.negative;
|
|
690
|
+
unignored = rule.negative;
|
|
691
|
+
matchedRule = rule.negative ? UNDEFINED : rule;
|
|
692
|
+
break;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
const ret = {
|
|
696
|
+
ignored,
|
|
697
|
+
unignored
|
|
698
|
+
};
|
|
699
|
+
if (matchedRule) {
|
|
700
|
+
ret.rule = matchedRule;
|
|
701
|
+
}
|
|
702
|
+
return ret;
|
|
703
|
+
}
|
|
667
704
|
// Test one single path without recursively checking parent directories
|
|
668
705
|
//
|
|
669
706
|
// - checkUnignored `boolean` whether should check if the path is unignored,
|
|
@@ -784,14 +821,12 @@ var require_ignore = __commonJS({
|
|
|
784
821
|
if (path.charCodeAt(path.length - 1) !== SLASH_CODE) {
|
|
785
822
|
return this.test(path);
|
|
786
823
|
}
|
|
787
|
-
const
|
|
788
|
-
if (
|
|
789
|
-
|
|
790
|
-
if (parent.ignored) {
|
|
791
|
-
return parent;
|
|
792
|
-
}
|
|
824
|
+
const dir = this._t(path, this._testCache, true);
|
|
825
|
+
if (dir.ignored) {
|
|
826
|
+
return dir;
|
|
793
827
|
}
|
|
794
|
-
|
|
828
|
+
const literal = this._rules.testLiteral(path);
|
|
829
|
+
return literal.ignored || literal.unignored ? literal : dir;
|
|
795
830
|
}
|
|
796
831
|
_t(path, cache2, checkUnignored) {
|
|
797
832
|
if (path in cache2) {
|
|
@@ -838,7 +873,7 @@ var require_ignore = __commonJS({
|
|
|
838
873
|
|
|
839
874
|
// src/session-start.ts
|
|
840
875
|
import { appendFileSync as appendFileSync2 } from "node:fs";
|
|
841
|
-
import { join as
|
|
876
|
+
import { join as join7 } from "node:path";
|
|
842
877
|
|
|
843
878
|
// ../agent-context/src/field-notes.ts
|
|
844
879
|
import { createHash } from "node:crypto";
|
|
@@ -847,7 +882,7 @@ var FIELD_NOTES_NOTE_TITLE = "Field notes for this sandbox";
|
|
|
847
882
|
var FIELD_NOTES_NOTE_HEADER = `## ${FIELD_NOTES_NOTE_TITLE}`;
|
|
848
883
|
var ALWAYS = ["meta"];
|
|
849
884
|
var ROW = /^(\d+),([a-z][a-z0-9_-]*),/;
|
|
850
|
-
var TOP_LEVEL = /^([a-z][a-z0-9_]*)(\[|:)/;
|
|
885
|
+
var TOP_LEVEL = /^([a-z][a-z0-9_-]*)(\[|:)/;
|
|
851
886
|
var blocksOf = (lines) => {
|
|
852
887
|
const opens = [];
|
|
853
888
|
for (const [at, line] of lines.entries()) {
|
|
@@ -943,8 +978,8 @@ var fieldNotes = ({ file: path, budget, onUnreadable, title = FIELD_NOTES_NOTE_T
|
|
|
943
978
|
};
|
|
944
979
|
|
|
945
980
|
// ../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";
|
|
981
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
|
|
982
|
+
import { basename, dirname, join as join2, relative, sep } from "node:path";
|
|
948
983
|
|
|
949
984
|
// ../../_shared/workspace-ignore/src/index.ts
|
|
950
985
|
var import_ignore = __toESM(require_ignore(), 1);
|
|
@@ -1000,6 +1035,96 @@ var firstSegment = (relPath) => {
|
|
|
1000
1035
|
var isReferencePath = (relPath) => firstSegment(relPath) === REFERENCE_DIR;
|
|
1001
1036
|
var isPublicPath = (relPath) => firstSegment(relPath) === PUBLIC_DIR;
|
|
1002
1037
|
|
|
1038
|
+
// ../agent-context/src/workspace-activity.ts
|
|
1039
|
+
import { execFileSync } from "node:child_process";
|
|
1040
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
1041
|
+
import { join } from "node:path";
|
|
1042
|
+
var RECENT_DAYS = 21;
|
|
1043
|
+
var RECENT_COMMITS = 400;
|
|
1044
|
+
var GIT_TIMEOUT_MS = 3e3;
|
|
1045
|
+
var QUIET_DIRS = /* @__PURE__ */ new Set(["generated", "dist", "locales", "baselines", "fixtures", "__snapshots__"]);
|
|
1046
|
+
var QUIET_FILE = /\.(md|lock|snap)$|(^|[-.])lock\.(json|ya?ml)$/;
|
|
1047
|
+
var SHELF_MIN_DIRS = 4;
|
|
1048
|
+
var changedFiles = (repoDir) => {
|
|
1049
|
+
try {
|
|
1050
|
+
const out = execFileSync(
|
|
1051
|
+
"git",
|
|
1052
|
+
["-C", repoDir, "log", `--since=${RECENT_DAYS}.days`, "-n", String(RECENT_COMMITS), "--no-merges", "--relative", "--name-only", "--format=%x1e"],
|
|
1053
|
+
{ encoding: "utf8", timeout: GIT_TIMEOUT_MS, stdio: ["ignore", "pipe", "ignore"], maxBuffer: 64 * 1024 * 1024 }
|
|
1054
|
+
);
|
|
1055
|
+
return out.split("").slice(1).map((commit) => commit.split("\n").filter((line) => line !== ""));
|
|
1056
|
+
} catch {
|
|
1057
|
+
return [];
|
|
1058
|
+
}
|
|
1059
|
+
};
|
|
1060
|
+
var isRepo = (dir) => existsSync(join(dir, ".git"));
|
|
1061
|
+
var isQuiet = (path) => {
|
|
1062
|
+
const segments = path.split("/");
|
|
1063
|
+
return QUIET_FILE.test(segments.at(-1) ?? "") || segments.slice(0, -1).some((segment) => segment.startsWith(".") || IGNORED_DIRS.has(segment) || QUIET_DIRS.has(segment));
|
|
1064
|
+
};
|
|
1065
|
+
var workspaceActivityOf = ({ projectRoot, areas }) => {
|
|
1066
|
+
const repos = [
|
|
1067
|
+
...isRepo(projectRoot) ? [{ dir: projectRoot, prefix: "" }] : [],
|
|
1068
|
+
...areas.filter((area) => isRepo(join(projectRoot, area))).map((area) => ({ dir: join(projectRoot, area), prefix: `${area}/` }))
|
|
1069
|
+
];
|
|
1070
|
+
const commits = repos.flatMap(({ dir, prefix }) => changedFiles(dir).map((files) => files.map((file) => `${prefix}${file}`)));
|
|
1071
|
+
const shelves = /* @__PURE__ */ new Map();
|
|
1072
|
+
const isShelf = (folder) => {
|
|
1073
|
+
const known = shelves.get(folder);
|
|
1074
|
+
if (known !== void 0) {
|
|
1075
|
+
return known;
|
|
1076
|
+
}
|
|
1077
|
+
let shelf = false;
|
|
1078
|
+
try {
|
|
1079
|
+
const entries = readdirSync(join(projectRoot, folder), { withFileTypes: true });
|
|
1080
|
+
const dirs = entries.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).length;
|
|
1081
|
+
const files = entries.filter((entry) => entry.isFile()).length;
|
|
1082
|
+
shelf = dirs >= SHELF_MIN_DIRS && files < dirs;
|
|
1083
|
+
} catch {
|
|
1084
|
+
}
|
|
1085
|
+
shelves.set(folder, shelf);
|
|
1086
|
+
return shelf;
|
|
1087
|
+
};
|
|
1088
|
+
const featureOf = (path) => {
|
|
1089
|
+
const dirs = path.split("/").slice(0, -1);
|
|
1090
|
+
if (dirs.length === 0) {
|
|
1091
|
+
return void 0;
|
|
1092
|
+
}
|
|
1093
|
+
const src = dirs.indexOf("src");
|
|
1094
|
+
const start = src >= 0 ? src + 2 : 3;
|
|
1095
|
+
let depth = Math.min(start, dirs.length);
|
|
1096
|
+
if (depth < dirs.length && isShelf(dirs.slice(0, depth).join("/"))) {
|
|
1097
|
+
depth += 1;
|
|
1098
|
+
}
|
|
1099
|
+
return dirs.slice(0, depth).join("/");
|
|
1100
|
+
};
|
|
1101
|
+
const byFolder = /* @__PURE__ */ new Map();
|
|
1102
|
+
const byFeature = /* @__PURE__ */ new Map();
|
|
1103
|
+
for (const files of commits) {
|
|
1104
|
+
const kept = files.filter((file) => !isQuiet(file));
|
|
1105
|
+
const folders = new Set(kept.flatMap((file) => file.split("/").slice(0, -1).map((_, at, dirs) => dirs.slice(0, at + 1).join("/"))));
|
|
1106
|
+
for (const folder of folders) {
|
|
1107
|
+
byFolder.set(folder, (byFolder.get(folder) ?? 0) + 1);
|
|
1108
|
+
}
|
|
1109
|
+
for (const feature of new Set(kept.map(featureOf).filter((folder) => folder !== void 0))) {
|
|
1110
|
+
byFeature.set(feature, (byFeature.get(feature) ?? 0) + 1);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
const hot = [...byFeature.entries()].map(([folder, count]) => ({ folder, commits: count })).toSorted((left, right) => right.commits - left.commits || left.folder.localeCompare(right.folder));
|
|
1114
|
+
return { commits: commits.length, byFolder, hot };
|
|
1115
|
+
};
|
|
1116
|
+
var groupedFolders = (folders) => {
|
|
1117
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1118
|
+
for (const folder of folders) {
|
|
1119
|
+
const cut = folder.lastIndexOf("/");
|
|
1120
|
+
const parent = cut === -1 ? "" : folder.slice(0, cut);
|
|
1121
|
+
groups.set(parent, [...groups.get(parent) ?? [], cut === -1 ? folder : folder.slice(cut + 1)]);
|
|
1122
|
+
}
|
|
1123
|
+
return [...groups.entries()].flatMap(
|
|
1124
|
+
([parent, names]) => parent === "" ? names : [`${parent}/${names.length === 1 ? names[0] ?? "" : `{${names.join(",")}}`}`]
|
|
1125
|
+
);
|
|
1126
|
+
};
|
|
1127
|
+
|
|
1003
1128
|
// ../agent-context/src/workspace-map.ts
|
|
1004
1129
|
var WORKSPACE_MAP_NOTE_HEADER = "## Map of this project";
|
|
1005
1130
|
var MAX_NOTE_CHARS = 2800;
|
|
@@ -1016,11 +1141,11 @@ var isBrowsable = (name, relPath) => !name.startsWith(".") && !IGNORED_DIRS.has(
|
|
|
1016
1141
|
var childDirs = (dir, root) => {
|
|
1017
1142
|
let entries;
|
|
1018
1143
|
try {
|
|
1019
|
-
entries =
|
|
1144
|
+
entries = readdirSync2(dir, { withFileTypes: true });
|
|
1020
1145
|
} catch {
|
|
1021
1146
|
return [];
|
|
1022
1147
|
}
|
|
1023
|
-
return entries.filter((entry) => entry.isDirectory() && isBrowsable(entry.name, posix(relative(root,
|
|
1148
|
+
return entries.filter((entry) => entry.isDirectory() && isBrowsable(entry.name, posix(relative(root, join2(dir, entry.name))))).map((entry) => entry.name).toSorted();
|
|
1024
1149
|
};
|
|
1025
1150
|
var readIfPresent = (path) => {
|
|
1026
1151
|
try {
|
|
@@ -1029,9 +1154,9 @@ var readIfPresent = (path) => {
|
|
|
1029
1154
|
return void 0;
|
|
1030
1155
|
}
|
|
1031
1156
|
};
|
|
1032
|
-
var hasManifest = (dir) => MANIFESTS.some((name) => readIfPresent(
|
|
1157
|
+
var hasManifest = (dir) => MANIFESTS.some((name) => readIfPresent(join2(dir, name)) !== void 0);
|
|
1033
1158
|
var describeManifest = (dir, name) => {
|
|
1034
|
-
const source = readIfPresent(
|
|
1159
|
+
const source = readIfPresent(join2(dir, name));
|
|
1035
1160
|
if (source === void 0) {
|
|
1036
1161
|
return void 0;
|
|
1037
1162
|
}
|
|
@@ -1053,7 +1178,7 @@ var describeManifest = (dir, name) => {
|
|
|
1053
1178
|
return found === void 0 || found === "" ? void 0 : found;
|
|
1054
1179
|
};
|
|
1055
1180
|
var describeReadme = (dir) => {
|
|
1056
|
-
const source = readIfPresent(
|
|
1181
|
+
const source = readIfPresent(join2(dir, "README.md")) ?? readIfPresent(join2(dir, "readme.md"));
|
|
1057
1182
|
if (source === void 0) {
|
|
1058
1183
|
return void 0;
|
|
1059
1184
|
}
|
|
@@ -1071,12 +1196,20 @@ var describeReadme = (dir) => {
|
|
|
1071
1196
|
}
|
|
1072
1197
|
return void 0;
|
|
1073
1198
|
};
|
|
1199
|
+
var firstSentence = (text) => {
|
|
1200
|
+
const plain = text.replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim();
|
|
1201
|
+
return /^(.+?[.!?])(?:\s|$)/.exec(plain)?.[1] ?? plain;
|
|
1202
|
+
};
|
|
1074
1203
|
var clip = (text, max) => {
|
|
1075
|
-
const oneLine = text
|
|
1204
|
+
const oneLine = firstSentence(text);
|
|
1076
1205
|
if (oneLine.length <= max) {
|
|
1077
1206
|
return oneLine;
|
|
1078
1207
|
}
|
|
1079
1208
|
const head = oneLine.slice(0, max);
|
|
1209
|
+
const clause = Math.max(...[", ", "; ", ": ", " \u2014 "].map((mark) => head.lastIndexOf(mark)));
|
|
1210
|
+
if (clause > max / 2) {
|
|
1211
|
+
return head.slice(0, clause);
|
|
1212
|
+
}
|
|
1080
1213
|
const lastSpace = head.lastIndexOf(" ");
|
|
1081
1214
|
return `${(lastSpace > max / 2 ? head.slice(0, lastSpace) : head).replace(/[.,;:]$/, "")}\u2026`;
|
|
1082
1215
|
};
|
|
@@ -1100,7 +1233,7 @@ var measure = (dir, root) => {
|
|
|
1100
1233
|
}
|
|
1101
1234
|
let entries;
|
|
1102
1235
|
try {
|
|
1103
|
-
entries =
|
|
1236
|
+
entries = readdirSync2(current, { withFileTypes: true });
|
|
1104
1237
|
} catch {
|
|
1105
1238
|
return;
|
|
1106
1239
|
}
|
|
@@ -1109,7 +1242,7 @@ var measure = (dir, root) => {
|
|
|
1109
1242
|
return;
|
|
1110
1243
|
}
|
|
1111
1244
|
visited += 1;
|
|
1112
|
-
const child =
|
|
1245
|
+
const child = join2(current, entry.name);
|
|
1113
1246
|
if (entry.isDirectory()) {
|
|
1114
1247
|
if (isBrowsable(entry.name, posix(relative(root, child)))) {
|
|
1115
1248
|
walk(child, depth + 1);
|
|
@@ -1137,7 +1270,7 @@ var projectRootOf = (root, cwd) => {
|
|
|
1137
1270
|
let current = cwd;
|
|
1138
1271
|
for (; ; ) {
|
|
1139
1272
|
try {
|
|
1140
|
-
statSync2(
|
|
1273
|
+
statSync2(join2(current, ".git"));
|
|
1141
1274
|
return current;
|
|
1142
1275
|
} catch {
|
|
1143
1276
|
}
|
|
@@ -1156,13 +1289,13 @@ var packagesIn = (dir, root) => {
|
|
|
1156
1289
|
return [];
|
|
1157
1290
|
}
|
|
1158
1291
|
const children = childDirs(dir, root);
|
|
1159
|
-
const bearing = children.filter((child) => hasManifest(
|
|
1160
|
-
return children.length >= CONTAINER_MIN_CHILDREN && bearing.length >= CONTAINER_MIN_CHILDREN ? bearing.map((child) => ({ name: child, dir:
|
|
1292
|
+
const bearing = children.filter((child) => hasManifest(join2(dir, child)));
|
|
1293
|
+
return children.length >= CONTAINER_MIN_CHILDREN && bearing.length >= CONTAINER_MIN_CHILDREN ? bearing.map((child) => ({ name: child, dir: join2(dir, child) })) : [];
|
|
1161
1294
|
};
|
|
1162
1295
|
var areaDirsOf = (projectRoot, root) => {
|
|
1163
1296
|
const names = childDirs(projectRoot, root);
|
|
1164
1297
|
const areas = names.map((name) => {
|
|
1165
|
-
const dir =
|
|
1298
|
+
const dir = join2(projectRoot, name);
|
|
1166
1299
|
return { name, dir, packages: packagesIn(dir, root) };
|
|
1167
1300
|
});
|
|
1168
1301
|
const shelf = areas.length <= 2 ? areas.find((area) => area.packages.length > 0) : void 0;
|
|
@@ -1262,11 +1395,41 @@ var render = (map, exactPaths) => {
|
|
|
1262
1395
|
const total = map.omitted + dropped;
|
|
1263
1396
|
return [...head, ...lines, ...total > 0 ? [` \u2026 and ${total} more`] : [], ...tail].join("\n");
|
|
1264
1397
|
};
|
|
1398
|
+
var COMPACT_AREAS = 6;
|
|
1399
|
+
var COMPACT_HOT = 6;
|
|
1400
|
+
var COMPACT_ACTIVE_SHARE = 0.03;
|
|
1401
|
+
var COMPACT_HOT_MIN = 2;
|
|
1402
|
+
var renderCompact = (map, exactPaths, activity) => {
|
|
1403
|
+
const project = map.project === "" ? "the workspace" : `\`${map.project}\``;
|
|
1404
|
+
const leaves = map.areas.flatMap((area) => area.children.length > 1 ? area.children : [area]);
|
|
1405
|
+
const busy = (area) => activity.byFolder.get(area.name) ?? 0;
|
|
1406
|
+
const ranked = activity.commits > 0 ? leaves.toSorted((left, right) => busy(right) - busy(left) || right.files - left.files || left.name.localeCompare(right.name)) : leaves.toSorted((left, right) => right.files - left.files || left.name.localeCompare(right.name));
|
|
1407
|
+
const active = (area, at) => at < COMPACT_AREAS && (activity.commits === 0 || busy(area) >= Math.max(1, activity.commits * COMPACT_ACTIVE_SHARE));
|
|
1408
|
+
const listed = ranked.filter((area, at) => area.here || active(area, at));
|
|
1409
|
+
const rest = leaves.filter((area) => !listed.includes(area)).map((area) => area.name);
|
|
1410
|
+
const unlisted = map.omitted + map.areas.reduce((sum, area) => sum + area.childrenOmitted, 0);
|
|
1411
|
+
const width = Math.min(Math.max(...listed.map((area) => area.name.length)) + 2, 34);
|
|
1412
|
+
const hot = groupedFolders(
|
|
1413
|
+
activity.hot.filter((entry) => entry.commits >= COMPACT_HOT_MIN).slice(0, COMPACT_HOT).map((entry) => entry.folder)
|
|
1414
|
+
);
|
|
1415
|
+
const where = map.cwd === map.project ? `You are at the top of ${project}.` : `You are here: \`${map.cwd}\`, in ${project}.`;
|
|
1416
|
+
return [
|
|
1417
|
+
WORKSPACE_MAP_NOTE_HEADER,
|
|
1418
|
+
"",
|
|
1419
|
+
`${where} This is its layout, so do not \`ls\` or \`tree\` the root to orient yourself; use ${exactPaths} for exact paths.`,
|
|
1420
|
+
"",
|
|
1421
|
+
...listed.map((area) => `${area.name.padEnd(width)}${area.purpose}${area.here ? " \u2190 you are here" : ""}`.trimEnd()),
|
|
1422
|
+
...rest.length > 0 || unlisted > 0 ? [`Also: ${groupedFolders(rest).join(", ")}${unlisted > 0 ? `${rest.length > 0 ? ", " : ""}and ${unlisted} smaller` : ""}`] : [],
|
|
1423
|
+
...map.siblings.length > 0 ? [`Also under the workspace root: ${map.siblings.map((name) => `${name}/`).join(", ")}`] : [],
|
|
1424
|
+
...hot.length > 0 ? ["", `Recent work (last 3 weeks) landed in: ${hot.join(" \xB7 ")}`] : []
|
|
1425
|
+
].join("\n");
|
|
1426
|
+
};
|
|
1265
1427
|
var TTL_MS = 6e4;
|
|
1266
1428
|
var cache = /* @__PURE__ */ new Map();
|
|
1267
1429
|
var workspaceMapNote = (input) => {
|
|
1268
1430
|
const exactPaths = input.exactPaths ?? "`iq files` or Read";
|
|
1269
|
-
const
|
|
1431
|
+
const form = input.form ?? "full";
|
|
1432
|
+
const key = `${input.root}\0${input.cwd}\0${exactPaths}\0${form}`;
|
|
1270
1433
|
const hit = cache.get(key);
|
|
1271
1434
|
if (hit !== void 0 && Date.now() - hit.at < TTL_MS) {
|
|
1272
1435
|
return hit.note;
|
|
@@ -1274,7 +1437,11 @@ var workspaceMapNote = (input) => {
|
|
|
1274
1437
|
let note;
|
|
1275
1438
|
try {
|
|
1276
1439
|
const map = workspaceMapOf(input);
|
|
1277
|
-
note = map === void 0 ? void 0 :
|
|
1440
|
+
note = map === void 0 ? void 0 : form === "compact" ? renderCompact(
|
|
1441
|
+
map,
|
|
1442
|
+
exactPaths,
|
|
1443
|
+
workspaceActivityOf({ projectRoot: join2(input.root, map.project), areas: map.areas.map((area) => area.name) })
|
|
1444
|
+
) : render(map, exactPaths);
|
|
1278
1445
|
} catch {
|
|
1279
1446
|
note = void 0;
|
|
1280
1447
|
}
|
|
@@ -1284,12 +1451,12 @@ var workspaceMapNote = (input) => {
|
|
|
1284
1451
|
|
|
1285
1452
|
// src/features.ts
|
|
1286
1453
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "node:fs";
|
|
1287
|
-
import { join as
|
|
1454
|
+
import { join as join4 } from "node:path";
|
|
1288
1455
|
|
|
1289
1456
|
// src/runtime.ts
|
|
1290
1457
|
import { spawn } from "node:child_process";
|
|
1291
1458
|
import { accessSync, closeSync, constants, mkdirSync, openSync, readFileSync as readFileSync3, statSync as statSync3, writeFileSync } from "node:fs";
|
|
1292
|
-
import { delimiter, dirname as dirname2, join as
|
|
1459
|
+
import { delimiter, dirname as dirname2, join as join3 } from "node:path";
|
|
1293
1460
|
var pluginRoot = (env = process.env) => env["CLAUDE_PLUGIN_ROOT"] ?? dirname2(import.meta.dirname);
|
|
1294
1461
|
var isMissing = (error) => {
|
|
1295
1462
|
const code = typeof error === "object" && error !== null ? error.code : void 0;
|
|
@@ -1297,7 +1464,7 @@ var isMissing = (error) => {
|
|
|
1297
1464
|
};
|
|
1298
1465
|
var pluginFile = (parts, env = process.env) => {
|
|
1299
1466
|
try {
|
|
1300
|
-
return readFileSync3(
|
|
1467
|
+
return readFileSync3(join3(pluginRoot(env), ...parts), "utf8");
|
|
1301
1468
|
} catch (error) {
|
|
1302
1469
|
if (isMissing(error)) {
|
|
1303
1470
|
return void 0;
|
|
@@ -1310,7 +1477,7 @@ var onPath = (name, env = process.env) => {
|
|
|
1310
1477
|
for (const dir of (env["PATH"] ?? "").split(delimiter)) {
|
|
1311
1478
|
for (const extension of extensions) {
|
|
1312
1479
|
try {
|
|
1313
|
-
accessSync(
|
|
1480
|
+
accessSync(join3(dir, `${name}${extension}`), constants.X_OK);
|
|
1314
1481
|
return true;
|
|
1315
1482
|
} catch {
|
|
1316
1483
|
}
|
|
@@ -1433,7 +1600,7 @@ var readOptions = (env = process.env) => {
|
|
|
1433
1600
|
});
|
|
1434
1601
|
return Object.fromEntries(entries);
|
|
1435
1602
|
};
|
|
1436
|
-
var optionsFile = (data) =>
|
|
1603
|
+
var optionsFile = (data) => join4(data, "options.json");
|
|
1437
1604
|
var saveOptions = (data, options) => {
|
|
1438
1605
|
mkdirSync2(data, { recursive: true });
|
|
1439
1606
|
writeFileSync2(optionsFile(data), `${JSON.stringify(options)}
|
|
@@ -1442,7 +1609,7 @@ var saveOptions = (data, options) => {
|
|
|
1442
1609
|
|
|
1443
1610
|
// src/hook-io.ts
|
|
1444
1611
|
import { homedir } from "node:os";
|
|
1445
|
-
import { join as
|
|
1612
|
+
import { join as join5 } from "node:path";
|
|
1446
1613
|
var readStdin = async () => {
|
|
1447
1614
|
const chunks = [];
|
|
1448
1615
|
for await (const chunk of process.stdin) {
|
|
@@ -1477,13 +1644,13 @@ var runHook = async (handle) => {
|
|
|
1477
1644
|
`);
|
|
1478
1645
|
}
|
|
1479
1646
|
};
|
|
1480
|
-
var dataDir = (env = process.env) => env["CLAUDE_PLUGIN_DATA"] ??
|
|
1647
|
+
var dataDir = (env = process.env) => env["CLAUDE_PLUGIN_DATA"] ?? join5(env["CLAUDE_CONFIG_DIR"] ?? join5(homedir(), ".claude"), "plugins", "data", "intentic-intentic");
|
|
1481
1648
|
var projectDir = (input, env = process.env) => env["CLAUDE_PROJECT_DIR"] ?? input.cwd ?? process.cwd();
|
|
1482
|
-
var fieldNotesFile = (project) =>
|
|
1649
|
+
var fieldNotesFile = (project) => join5(project, ".claude", "intentic", "field-notes.toon");
|
|
1483
1650
|
|
|
1484
1651
|
// src/sessions.ts
|
|
1485
1652
|
import { appendFileSync, mkdirSync as mkdirSync3, readFileSync as readFileSync5 } from "node:fs";
|
|
1486
|
-
import { dirname as dirname3, join as
|
|
1653
|
+
import { dirname as dirname3, join as join6 } from "node:path";
|
|
1487
1654
|
|
|
1488
1655
|
// ../agent-context/src/experiments.ts
|
|
1489
1656
|
import { createHash as createHash2 } from "node:crypto";
|
|
@@ -1513,7 +1680,7 @@ var armsOf = (options, session) => {
|
|
|
1513
1680
|
};
|
|
1514
1681
|
var sends = (options, arms, mechanism) => MECHANISM_ON[mechanism](options) && arms[mechanism] !== false;
|
|
1515
1682
|
var measuredArms = (arms, offered) => Object.fromEntries(Object.entries(arms).filter(([mechanism]) => offered[mechanism] === true));
|
|
1516
|
-
var sessionsFile = (data) =>
|
|
1683
|
+
var sessionsFile = (data) => join6(data, "sessions.jsonl");
|
|
1517
1684
|
var recordSession = (data, row) => {
|
|
1518
1685
|
const file = sessionsFile(data);
|
|
1519
1686
|
mkdirSync3(dirname3(file), { recursive: true });
|
|
@@ -1530,7 +1697,7 @@ var compose = (options, input, project, arms, data, env) => {
|
|
|
1530
1697
|
const context = [];
|
|
1531
1698
|
const notices = [];
|
|
1532
1699
|
const notice = (id, text) => {
|
|
1533
|
-
if (claimIfDue(
|
|
1700
|
+
if (claimIfDue(join7(data, "notices", `${id}.stamp`), NOTICE_EVERY_MS)) {
|
|
1534
1701
|
notices.push(text);
|
|
1535
1702
|
}
|
|
1536
1703
|
};
|
|
@@ -1570,7 +1737,7 @@ var compose = (options, input, project, arms, data, env) => {
|
|
|
1570
1737
|
${nudge.trim()}`);
|
|
1571
1738
|
sent.iq = true;
|
|
1572
1739
|
}
|
|
1573
|
-
startDetached("iq", ["sessions", "ingest"], { cwd: project, log:
|
|
1740
|
+
startDetached("iq", ["sessions", "ingest"], { cwd: project, log: join7(data, "iq", `${projectSlug(project)}.ingest.log`), env });
|
|
1574
1741
|
} else {
|
|
1575
1742
|
notice("iq-missing", "intentic: iq search is on but the `iq` CLI is not installed (`npm i -g @intentic/iq`), so nothing was taught.");
|
|
1576
1743
|
}
|