@driftless-sh/cli 0.1.25 → 0.1.26
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/dist/index.js +274 -284
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -445,7 +445,7 @@ var require_util = __commonJS({
|
|
|
445
445
|
return path;
|
|
446
446
|
}
|
|
447
447
|
exports2.normalize = normalize;
|
|
448
|
-
function
|
|
448
|
+
function join2(aRoot, aPath) {
|
|
449
449
|
if (aRoot === "") {
|
|
450
450
|
aRoot = ".";
|
|
451
451
|
}
|
|
@@ -477,7 +477,7 @@ var require_util = __commonJS({
|
|
|
477
477
|
}
|
|
478
478
|
return joined;
|
|
479
479
|
}
|
|
480
|
-
exports2.join =
|
|
480
|
+
exports2.join = join2;
|
|
481
481
|
exports2.isAbsolute = function(aPath) {
|
|
482
482
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
483
483
|
};
|
|
@@ -650,7 +650,7 @@ var require_util = __commonJS({
|
|
|
650
650
|
parsed.path = parsed.path.substring(0, index + 1);
|
|
651
651
|
}
|
|
652
652
|
}
|
|
653
|
-
sourceURL =
|
|
653
|
+
sourceURL = join2(urlGenerate(parsed), sourceURL);
|
|
654
654
|
}
|
|
655
655
|
return normalize(sourceURL);
|
|
656
656
|
}
|
|
@@ -23019,8 +23019,8 @@ ${lanes.join("\n")}
|
|
|
23019
23019
|
function containsInvalidEscapeFlag(node) {
|
|
23020
23020
|
return !!((node.templateFlags || 0) & 2048);
|
|
23021
23021
|
}
|
|
23022
|
-
function hasInvalidEscape(
|
|
23023
|
-
return
|
|
23022
|
+
function hasInvalidEscape(template) {
|
|
23023
|
+
return template && !!(isNoSubstitutionTemplateLiteral(template) ? containsInvalidEscapeFlag(template) : containsInvalidEscapeFlag(template.head) || some(template.templateSpans, (span) => containsInvalidEscapeFlag(span.literal)));
|
|
23024
23024
|
}
|
|
23025
23025
|
var doubleQuoteEscapedCharsRegExp = /[\\"\u0000-\u001f\u2028\u2029\u0085]/g;
|
|
23026
23026
|
var singleQuoteEscapedCharsRegExp = /[\\'\u0000-\u001f\u2028\u2029\u0085]/g;
|
|
@@ -30345,7 +30345,7 @@ ${lanes.join("\n")}
|
|
|
30345
30345
|
function updateNewExpression(node, expression, typeArguments, argumentsArray) {
|
|
30346
30346
|
return node.expression !== expression || node.typeArguments !== typeArguments || node.arguments !== argumentsArray ? update(createNewExpression(expression, typeArguments, argumentsArray), node) : node;
|
|
30347
30347
|
}
|
|
30348
|
-
function createTaggedTemplateExpression(tag, typeArguments,
|
|
30348
|
+
function createTaggedTemplateExpression(tag, typeArguments, template) {
|
|
30349
30349
|
const node = createBaseNode(
|
|
30350
30350
|
216
|
|
30351
30351
|
/* TaggedTemplateExpression */
|
|
@@ -30356,7 +30356,7 @@ ${lanes.join("\n")}
|
|
|
30356
30356
|
false
|
|
30357
30357
|
);
|
|
30358
30358
|
node.typeArguments = asNodeArray(typeArguments);
|
|
30359
|
-
node.template =
|
|
30359
|
+
node.template = template;
|
|
30360
30360
|
node.transformFlags |= propagateChildFlags(node.tag) | propagateChildrenFlags(node.typeArguments) | propagateChildFlags(node.template) | 1024;
|
|
30361
30361
|
if (node.typeArguments) {
|
|
30362
30362
|
node.transformFlags |= 1;
|
|
@@ -30366,8 +30366,8 @@ ${lanes.join("\n")}
|
|
|
30366
30366
|
}
|
|
30367
30367
|
return node;
|
|
30368
30368
|
}
|
|
30369
|
-
function updateTaggedTemplateExpression(node, tag, typeArguments,
|
|
30370
|
-
return node.tag !== tag || node.typeArguments !== typeArguments || node.template !==
|
|
30369
|
+
function updateTaggedTemplateExpression(node, tag, typeArguments, template) {
|
|
30370
|
+
return node.tag !== tag || node.typeArguments !== typeArguments || node.template !== template ? update(createTaggedTemplateExpression(tag, typeArguments, template), node) : node;
|
|
30371
30371
|
}
|
|
30372
30372
|
function createTypeAssertion(type, expression) {
|
|
30373
30373
|
const node = createBaseNode(
|
|
@@ -73219,14 +73219,14 @@ ${lanes.join("\n")}
|
|
|
73219
73219
|
while (i > 0) {
|
|
73220
73220
|
i--;
|
|
73221
73221
|
const t = types[i];
|
|
73222
|
-
if (t.flags & 128 && some(templates, (
|
|
73222
|
+
if (t.flags & 128 && some(templates, (template) => isTypeMatchedByTemplateLiteralOrStringMapping(t, template))) {
|
|
73223
73223
|
orderedRemoveItemAt(types, i);
|
|
73224
73224
|
}
|
|
73225
73225
|
}
|
|
73226
73226
|
}
|
|
73227
73227
|
}
|
|
73228
|
-
function isTypeMatchedByTemplateLiteralOrStringMapping(type,
|
|
73229
|
-
return
|
|
73228
|
+
function isTypeMatchedByTemplateLiteralOrStringMapping(type, template) {
|
|
73229
|
+
return template.flags & 134217728 ? isTypeMatchedByTemplateLiteralType(type, template) : isMemberOfStringMapping(type, template);
|
|
73230
73230
|
}
|
|
73231
73231
|
function removeConstrainedTypeVariables(types) {
|
|
73232
73232
|
const typeVariables = [];
|
|
@@ -85395,9 +85395,9 @@ ${lanes.join("\n")}
|
|
|
85395
85395
|
const signature = getDecoratorCallSignature(decorator);
|
|
85396
85396
|
return signature ? getOrCreateTypeFromSignature(signature) : void 0;
|
|
85397
85397
|
}
|
|
85398
|
-
function getContextualTypeForSubstitutionExpression(
|
|
85399
|
-
if (
|
|
85400
|
-
return getContextualTypeForArgument(
|
|
85398
|
+
function getContextualTypeForSubstitutionExpression(template, substitutionExpression) {
|
|
85399
|
+
if (template.parent.kind === 216) {
|
|
85400
|
+
return getContextualTypeForArgument(template.parent, substitutionExpression);
|
|
85401
85401
|
}
|
|
85402
85402
|
return void 0;
|
|
85403
85403
|
}
|
|
@@ -89022,10 +89022,10 @@ ${lanes.join("\n")}
|
|
|
89022
89022
|
return [createSyntheticExpression(node, emptyFreshJsxObjectType)];
|
|
89023
89023
|
}
|
|
89024
89024
|
if (node.kind === 216) {
|
|
89025
|
-
const
|
|
89026
|
-
const args2 = [createSyntheticExpression(
|
|
89027
|
-
if (
|
|
89028
|
-
forEach(
|
|
89025
|
+
const template = node.template;
|
|
89026
|
+
const args2 = [createSyntheticExpression(template, getGlobalTemplateStringsArrayType())];
|
|
89027
|
+
if (template.kind === 229) {
|
|
89028
|
+
forEach(template.templateSpans, (span) => {
|
|
89029
89029
|
args2.push(span.expression);
|
|
89030
89030
|
});
|
|
89031
89031
|
}
|
|
@@ -107909,18 +107909,18 @@ ${lanes.join("\n")}
|
|
|
107909
107909
|
const templateArguments = [void 0];
|
|
107910
107910
|
const cookedStrings = [];
|
|
107911
107911
|
const rawStrings = [];
|
|
107912
|
-
const
|
|
107913
|
-
if (level === 0 && !hasInvalidEscape(
|
|
107912
|
+
const template = node.template;
|
|
107913
|
+
if (level === 0 && !hasInvalidEscape(template)) {
|
|
107914
107914
|
return visitEachChild(node, visitor, context);
|
|
107915
107915
|
}
|
|
107916
107916
|
const { factory: factory2 } = context;
|
|
107917
|
-
if (isNoSubstitutionTemplateLiteral(
|
|
107918
|
-
cookedStrings.push(createTemplateCooked(factory2,
|
|
107919
|
-
rawStrings.push(getRawLiteral(factory2,
|
|
107917
|
+
if (isNoSubstitutionTemplateLiteral(template)) {
|
|
107918
|
+
cookedStrings.push(createTemplateCooked(factory2, template));
|
|
107919
|
+
rawStrings.push(getRawLiteral(factory2, template, currentSourceFile));
|
|
107920
107920
|
} else {
|
|
107921
|
-
cookedStrings.push(createTemplateCooked(factory2,
|
|
107922
|
-
rawStrings.push(getRawLiteral(factory2,
|
|
107923
|
-
for (const templateSpan of
|
|
107921
|
+
cookedStrings.push(createTemplateCooked(factory2, template.head));
|
|
107922
|
+
rawStrings.push(getRawLiteral(factory2, template.head, currentSourceFile));
|
|
107923
|
+
for (const templateSpan of template.templateSpans) {
|
|
107924
107924
|
cookedStrings.push(createTemplateCooked(factory2, templateSpan.literal));
|
|
107925
107925
|
rawStrings.push(getRawLiteral(factory2, templateSpan.literal, currentSourceFile));
|
|
107926
107926
|
templateArguments.push(Debug.checkDefined(visitNode(templateSpan.expression, visitor, isExpression)));
|
|
@@ -107950,8 +107950,8 @@ ${lanes.join("\n")}
|
|
|
107950
107950
|
templateArguments
|
|
107951
107951
|
);
|
|
107952
107952
|
}
|
|
107953
|
-
function createTemplateCooked(factory2,
|
|
107954
|
-
return
|
|
107953
|
+
function createTemplateCooked(factory2, template) {
|
|
107954
|
+
return template.templateFlags & 26656 ? factory2.createVoidZero() : factory2.createStringLiteral(template.text);
|
|
107955
107955
|
}
|
|
107956
107956
|
function getRawLiteral(factory2, node, currentSourceFile) {
|
|
107957
107957
|
let text = node.rawText;
|
|
@@ -114494,13 +114494,13 @@ ${lanes.join("\n")}
|
|
|
114494
114494
|
const boundTag = factory2.createFunctionBindCall(tag, classThis, []);
|
|
114495
114495
|
setOriginalNode(boundTag, node);
|
|
114496
114496
|
setTextRange(boundTag, node);
|
|
114497
|
-
const
|
|
114497
|
+
const template = visitNode(node.template, visitor, isTemplateLiteral);
|
|
114498
114498
|
return factory2.updateTaggedTemplateExpression(
|
|
114499
114499
|
node,
|
|
114500
114500
|
boundTag,
|
|
114501
114501
|
/*typeArguments*/
|
|
114502
114502
|
void 0,
|
|
114503
|
-
|
|
114503
|
+
template
|
|
114504
114504
|
);
|
|
114505
114505
|
}
|
|
114506
114506
|
return visitEachChild(node, visitor, context);
|
|
@@ -146943,7 +146943,7 @@ ${lanes.join("\n")}
|
|
|
146943
146943
|
};
|
|
146944
146944
|
}
|
|
146945
146945
|
function createBuildOrUpdateInvalidedProject(state, project, projectPath, projectIndex, config, status, buildOrder) {
|
|
146946
|
-
let
|
|
146946
|
+
let step2 = 0;
|
|
146947
146947
|
let program;
|
|
146948
146948
|
let buildResult;
|
|
146949
146949
|
return {
|
|
@@ -147019,14 +147019,14 @@ ${lanes.join("\n")}
|
|
|
147019
147019
|
if (state.options.dry) {
|
|
147020
147020
|
reportStatus(state, Diagnostics.A_non_dry_build_would_build_project_0, project);
|
|
147021
147021
|
buildResult = 1;
|
|
147022
|
-
|
|
147022
|
+
step2 = 2;
|
|
147023
147023
|
return;
|
|
147024
147024
|
}
|
|
147025
147025
|
if (state.options.verbose) reportStatus(state, Diagnostics.Building_project_0, project);
|
|
147026
147026
|
if (config.fileNames.length === 0) {
|
|
147027
147027
|
reportAndStoreErrors(state, projectPath, getConfigFileParsingDiagnostics(config));
|
|
147028
147028
|
buildResult = 0;
|
|
147029
|
-
|
|
147029
|
+
step2 = 2;
|
|
147030
147030
|
return;
|
|
147031
147031
|
}
|
|
147032
147032
|
const { host, compilerHost } = state;
|
|
@@ -147052,13 +147052,13 @@ ${lanes.join("\n")}
|
|
|
147052
147052
|
);
|
|
147053
147053
|
state.builderPrograms.set(projectPath, program);
|
|
147054
147054
|
}
|
|
147055
|
-
|
|
147055
|
+
step2++;
|
|
147056
147056
|
}
|
|
147057
147057
|
function emit(writeFileCallback, cancellationToken, customTransformers) {
|
|
147058
147058
|
var _a, _b, _c;
|
|
147059
147059
|
Debug.assertIsDefined(program);
|
|
147060
147060
|
Debug.assert(
|
|
147061
|
-
|
|
147061
|
+
step2 === 1
|
|
147062
147062
|
/* Emit */
|
|
147063
147063
|
);
|
|
147064
147064
|
const { host, compilerHost } = state;
|
|
@@ -147130,13 +147130,13 @@ ${lanes.join("\n")}
|
|
|
147130
147130
|
buildResult |= 4;
|
|
147131
147131
|
}
|
|
147132
147132
|
afterProgramDone(state, program);
|
|
147133
|
-
|
|
147133
|
+
step2 = 2;
|
|
147134
147134
|
return emitResult;
|
|
147135
147135
|
}
|
|
147136
147136
|
function executeSteps(till, cancellationToken, writeFile2, customTransformers) {
|
|
147137
|
-
while (
|
|
147138
|
-
const currentStep =
|
|
147139
|
-
switch (
|
|
147137
|
+
while (step2 <= till && step2 < 3) {
|
|
147138
|
+
const currentStep = step2;
|
|
147139
|
+
switch (step2) {
|
|
147140
147140
|
case 0:
|
|
147141
147141
|
createProgram2();
|
|
147142
147142
|
break;
|
|
@@ -147145,14 +147145,14 @@ ${lanes.join("\n")}
|
|
|
147145
147145
|
break;
|
|
147146
147146
|
case 2:
|
|
147147
147147
|
queueReferencingProjects(state, project, projectPath, projectIndex, config, buildOrder, Debug.checkDefined(buildResult));
|
|
147148
|
-
|
|
147148
|
+
step2++;
|
|
147149
147149
|
break;
|
|
147150
147150
|
// Should never be done
|
|
147151
147151
|
case 3:
|
|
147152
147152
|
default:
|
|
147153
|
-
assertType(
|
|
147153
|
+
assertType(step2);
|
|
147154
147154
|
}
|
|
147155
|
-
Debug.assert(
|
|
147155
|
+
Debug.assert(step2 > currentStep);
|
|
147156
147156
|
}
|
|
147157
147157
|
}
|
|
147158
147158
|
}
|
|
@@ -159531,12 +159531,12 @@ interface Symbol {
|
|
|
159531
159531
|
void 0,
|
|
159532
159532
|
typeParameter.name
|
|
159533
159533
|
);
|
|
159534
|
-
const
|
|
159534
|
+
const template = factory.createJSDocTemplateTag(
|
|
159535
159535
|
factory.createIdentifier("template"),
|
|
159536
159536
|
constraint && cast(constraint, isJSDocTypeExpression),
|
|
159537
159537
|
[parameter]
|
|
159538
159538
|
);
|
|
159539
|
-
templates.push(
|
|
159539
|
+
templates.push(template);
|
|
159540
159540
|
});
|
|
159541
159541
|
const jsDoc = factory.createJSDocComment(
|
|
159542
159542
|
/*comment*/
|
|
@@ -191190,11 +191190,11 @@ ${content}
|
|
|
191190
191190
|
return createTextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
|
|
191191
191191
|
}
|
|
191192
191192
|
function getApplicableSpanForTaggedTemplate(taggedTemplate, sourceFile) {
|
|
191193
|
-
const
|
|
191194
|
-
const applicableSpanStart =
|
|
191195
|
-
let applicableSpanEnd =
|
|
191196
|
-
if (
|
|
191197
|
-
const lastSpan = last(
|
|
191193
|
+
const template = taggedTemplate.template;
|
|
191194
|
+
const applicableSpanStart = template.getStart();
|
|
191195
|
+
let applicableSpanEnd = template.getEnd();
|
|
191196
|
+
if (template.kind === 229) {
|
|
191197
|
+
const lastSpan = last(template.templateSpans);
|
|
191198
191198
|
if (lastSpan.literal.getFullWidth() === 0) {
|
|
191199
191199
|
applicableSpanEnd = skipTrivia(
|
|
191200
191200
|
sourceFile.text,
|
|
@@ -214431,8 +214431,119 @@ function formatError(e) {
|
|
|
214431
214431
|
// src/commands/init.ts
|
|
214432
214432
|
init_git();
|
|
214433
214433
|
var import_scanner = __toESM(require_dist());
|
|
214434
|
+
var import_node_fs4 = require("node:fs");
|
|
214435
|
+
var import_node_path4 = require("node:path");
|
|
214436
|
+
|
|
214437
|
+
// src/commands/install-skill.ts
|
|
214434
214438
|
var import_node_fs3 = require("node:fs");
|
|
214435
214439
|
var import_node_path3 = require("node:path");
|
|
214440
|
+
var SKILL_URL = "https://raw.githubusercontent.com/driftless-gh/driftless-skill/main/skills/driftless/SKILL.md";
|
|
214441
|
+
var AGENTS_BLOCK = `
|
|
214442
|
+
## Driftless \u2014 Context Integrity
|
|
214443
|
+
|
|
214444
|
+
Before touching files:
|
|
214445
|
+
driftless context push --files "<files you're about to edit>"
|
|
214446
|
+
|
|
214447
|
+
Before pushing:
|
|
214448
|
+
driftless scan --diff
|
|
214449
|
+
|
|
214450
|
+
Save discoveries:
|
|
214451
|
+
driftless context update <slug> --gotchas "..." --decisions "..."
|
|
214452
|
+
|
|
214453
|
+
Full skill \u2192 https://github.com/driftless-gh/driftless-skill
|
|
214454
|
+
`;
|
|
214455
|
+
async function downloadSkill(cwd) {
|
|
214456
|
+
const driftlessDir = (0, import_node_path3.resolve)(cwd, ".driftless");
|
|
214457
|
+
if (!(0, import_node_fs3.existsSync)(driftlessDir)) {
|
|
214458
|
+
(0, import_node_fs3.mkdirSync)(driftlessDir, { recursive: true });
|
|
214459
|
+
}
|
|
214460
|
+
const skillPath = (0, import_node_path3.resolve)(driftlessDir, "skill.md");
|
|
214461
|
+
try {
|
|
214462
|
+
const { default: https } = await import("node:https");
|
|
214463
|
+
const { default: http } = await import("node:http");
|
|
214464
|
+
const url = new URL(SKILL_URL);
|
|
214465
|
+
const client = url.protocol === "https:" ? https : http;
|
|
214466
|
+
await new Promise((ok, fail) => {
|
|
214467
|
+
client.get(SKILL_URL, (res) => {
|
|
214468
|
+
if (res.statusCode !== 200) {
|
|
214469
|
+
fail(new Error(`HTTP ${res.statusCode}`));
|
|
214470
|
+
return;
|
|
214471
|
+
}
|
|
214472
|
+
const chunks = [];
|
|
214473
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
214474
|
+
res.on("end", () => {
|
|
214475
|
+
(0, import_node_fs3.writeFileSync)(skillPath, Buffer.concat(chunks), "utf-8");
|
|
214476
|
+
ok();
|
|
214477
|
+
});
|
|
214478
|
+
res.on("error", fail);
|
|
214479
|
+
}).on("error", fail);
|
|
214480
|
+
});
|
|
214481
|
+
} catch {
|
|
214482
|
+
(0, import_node_fs3.writeFileSync)(
|
|
214483
|
+
skillPath,
|
|
214484
|
+
`# Driftless Skill
|
|
214485
|
+
|
|
214486
|
+
See https://github.com/driftless-gh/driftless-skill for the full skill.
|
|
214487
|
+
`,
|
|
214488
|
+
"utf-8"
|
|
214489
|
+
);
|
|
214490
|
+
}
|
|
214491
|
+
}
|
|
214492
|
+
function handleClaudeMd(cwd) {
|
|
214493
|
+
const claudePath = (0, import_node_path3.resolve)(cwd, "CLAUDE.md");
|
|
214494
|
+
const reference = "@.driftless/skill.md";
|
|
214495
|
+
if (!(0, import_node_fs3.existsSync)(claudePath)) {
|
|
214496
|
+
(0, import_node_fs3.writeFileSync)(claudePath, `${reference}
|
|
214497
|
+
`, "utf-8");
|
|
214498
|
+
return "created";
|
|
214499
|
+
}
|
|
214500
|
+
const existing = (0, import_node_fs3.readFileSync)(claudePath, "utf-8");
|
|
214501
|
+
if (existing.includes(reference)) {
|
|
214502
|
+
return "already configured";
|
|
214503
|
+
}
|
|
214504
|
+
const needsNewline = existing.length > 0 && !existing.endsWith("\n");
|
|
214505
|
+
(0, import_node_fs3.writeFileSync)(claudePath, existing + (needsNewline ? "\n" : "") + `
|
|
214506
|
+
${reference}
|
|
214507
|
+
`, "utf-8");
|
|
214508
|
+
return "updated";
|
|
214509
|
+
}
|
|
214510
|
+
function handleAgentsMd(cwd) {
|
|
214511
|
+
const agentsPath = (0, import_node_path3.resolve)(cwd, "AGENTS.md");
|
|
214512
|
+
if (!(0, import_node_fs3.existsSync)(agentsPath)) {
|
|
214513
|
+
(0, import_node_fs3.writeFileSync)(agentsPath, AGENTS_BLOCK.trimStart(), "utf-8");
|
|
214514
|
+
return "created";
|
|
214515
|
+
}
|
|
214516
|
+
const existing = (0, import_node_fs3.readFileSync)(agentsPath, "utf-8");
|
|
214517
|
+
if (existing.includes("## Driftless")) {
|
|
214518
|
+
return "already configured";
|
|
214519
|
+
}
|
|
214520
|
+
const needsNewline = existing.length > 0 && !existing.endsWith("\n");
|
|
214521
|
+
(0, import_node_fs3.writeFileSync)(agentsPath, existing + (needsNewline ? "\n" : "") + AGENTS_BLOCK, "utf-8");
|
|
214522
|
+
return "updated";
|
|
214523
|
+
}
|
|
214524
|
+
async function runInstallSkill(cwd) {
|
|
214525
|
+
await downloadSkill(cwd);
|
|
214526
|
+
const claudeMd = handleClaudeMd(cwd);
|
|
214527
|
+
const agentsMd = handleAgentsMd(cwd);
|
|
214528
|
+
return { claudeMd, agentsMd };
|
|
214529
|
+
}
|
|
214530
|
+
async function installSkillCommand() {
|
|
214531
|
+
const cwd = process.cwd();
|
|
214532
|
+
const result = await runInstallSkill(cwd);
|
|
214533
|
+
const icon = (s) => s === "created" ? "created \u2713" : s === "updated" ? "updated \u2713" : "already configured \u2713";
|
|
214534
|
+
console.log(` CLAUDE.md ${icon(result.claudeMd)}`);
|
|
214535
|
+
console.log(` AGENTS.md ${icon(result.agentsMd)}`);
|
|
214536
|
+
return result;
|
|
214537
|
+
}
|
|
214538
|
+
|
|
214539
|
+
// src/commands/init.ts
|
|
214540
|
+
function getVersion() {
|
|
214541
|
+
try {
|
|
214542
|
+
return "0.1.26";
|
|
214543
|
+
} catch {
|
|
214544
|
+
return "0.0.0";
|
|
214545
|
+
}
|
|
214546
|
+
}
|
|
214436
214547
|
function analyzeCodePatterns(components) {
|
|
214437
214548
|
const pattern = {
|
|
214438
214549
|
guardNames: [],
|
|
@@ -214690,15 +214801,15 @@ function detectExistingDocs(cwd) {
|
|
|
214690
214801
|
{ path: "README.md", name: "readme", what: "Project overview and setup", pattern: void 0 }
|
|
214691
214802
|
];
|
|
214692
214803
|
for (const candidate of candidates) {
|
|
214693
|
-
const fullPath = (0,
|
|
214694
|
-
if ((0,
|
|
214804
|
+
const fullPath = (0, import_node_path4.resolve)(cwd, candidate.path);
|
|
214805
|
+
if ((0, import_node_fs4.existsSync)(fullPath)) {
|
|
214695
214806
|
docs.push({ path: candidate.path, name: candidate.name, what: candidate.what, pattern: candidate.pattern });
|
|
214696
214807
|
}
|
|
214697
214808
|
}
|
|
214698
|
-
const docsDir = (0,
|
|
214699
|
-
if ((0,
|
|
214809
|
+
const docsDir = (0, import_node_path4.resolve)(cwd, "docs");
|
|
214810
|
+
if ((0, import_node_fs4.existsSync)(docsDir)) {
|
|
214700
214811
|
try {
|
|
214701
|
-
const entries = (0,
|
|
214812
|
+
const entries = (0, import_node_fs4.readdirSync)(docsDir, { withFileTypes: true });
|
|
214702
214813
|
for (const entry of entries) {
|
|
214703
214814
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
214704
214815
|
const existingPath = candidates.find((c) => c.path === `docs/${entry.name}`);
|
|
@@ -214718,8 +214829,23 @@ function detectExistingDocs(cwd) {
|
|
|
214718
214829
|
}
|
|
214719
214830
|
return docs;
|
|
214720
214831
|
}
|
|
214832
|
+
var DIVIDER = "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500";
|
|
214833
|
+
var DOT_TOTAL = 36;
|
|
214834
|
+
function step(label, value) {
|
|
214835
|
+
const prefix = ` \u2192 ${label}`;
|
|
214836
|
+
const dots = ".".repeat(Math.max(2, DOT_TOTAL - prefix.length));
|
|
214837
|
+
console.log(`${prefix}${dots} ${value}`);
|
|
214838
|
+
}
|
|
214721
214839
|
async function initCommand(args) {
|
|
214722
|
-
|
|
214840
|
+
const version = getVersion();
|
|
214841
|
+
console.log("D R I F T L E S S");
|
|
214842
|
+
console.log(`v${version}`);
|
|
214843
|
+
console.log("");
|
|
214844
|
+
console.log("AI ships fast. Humans lose context faster.");
|
|
214845
|
+
console.log("Driftless fixes that.");
|
|
214846
|
+
console.log("");
|
|
214847
|
+
console.log(DIVIDER);
|
|
214848
|
+
console.log("");
|
|
214723
214849
|
if (!isGitRepo()) {
|
|
214724
214850
|
console.error("Error: not a git repository.");
|
|
214725
214851
|
process.exit(1);
|
|
@@ -214729,8 +214855,6 @@ async function initCommand(args) {
|
|
|
214729
214855
|
console.error("Error: no git remote found.");
|
|
214730
214856
|
process.exit(1);
|
|
214731
214857
|
}
|
|
214732
|
-
console.log(`Repository: ${remote.org}/${remote.repo}`);
|
|
214733
|
-
console.log("\nConnecting to Driftless Cloud...");
|
|
214734
214858
|
let workspace;
|
|
214735
214859
|
try {
|
|
214736
214860
|
workspace = await api.get("/me");
|
|
@@ -214738,15 +214862,18 @@ async function initCommand(args) {
|
|
|
214738
214862
|
console.error("Could not resolve workspace. Check your API key.");
|
|
214739
214863
|
process.exit(1);
|
|
214740
214864
|
}
|
|
214741
|
-
console.log(` Workspace: ${workspace.slug} \u2713`);
|
|
214742
214865
|
} catch (err) {
|
|
214743
|
-
console.error(`
|
|
214866
|
+
console.error(`Failed to connect: ${err?.message || "unreachable"}`);
|
|
214744
214867
|
process.exit(1);
|
|
214745
214868
|
}
|
|
214746
214869
|
const workspaceSlug = workspace.slug;
|
|
214747
|
-
console.log(
|
|
214870
|
+
console.log(`Repository: ${remote.org}/${remote.repo}`);
|
|
214871
|
+
console.log(`Workspace: ${workspaceSlug} \u2713`);
|
|
214872
|
+
console.log("");
|
|
214748
214873
|
const cwd = process.cwd();
|
|
214874
|
+
const scanStart = Date.now();
|
|
214749
214875
|
const scanResult = await (0, import_scanner.scanRepo)(cwd);
|
|
214876
|
+
const scanMs = Date.now() - scanStart;
|
|
214750
214877
|
const earlyPatterns = analyzeCodePatterns(scanResult.components);
|
|
214751
214878
|
const summary = {
|
|
214752
214879
|
endpoints: scanResult.stats.total_endpoints,
|
|
@@ -214773,36 +214900,31 @@ async function initCommand(args) {
|
|
|
214773
214900
|
const actualServices = components.filter((c) => c.type === "service").length;
|
|
214774
214901
|
const actualModules = components.filter((c) => c.type === "module").length;
|
|
214775
214902
|
const actualGuards = components.filter((c) => c.type === "guard").length;
|
|
214776
|
-
const
|
|
214777
|
-
|
|
214778
|
-
|
|
214779
|
-
|
|
214780
|
-
|
|
214781
|
-
|
|
214782
|
-
|
|
214783
|
-
if (
|
|
214784
|
-
console.log(`
|
|
214785
|
-
}
|
|
214786
|
-
|
|
214787
|
-
const t = scanResult.telemetry;
|
|
214788
|
-
console.log(` Scan: ${t.duration_ms}ms, ${t.memory_mb}MB heap, ${t.files_parsed} files`);
|
|
214903
|
+
const frameworkLabel = [summary.framework, "ts"].filter(Boolean).join(", ");
|
|
214904
|
+
step("detecting framework", frameworkLabel);
|
|
214905
|
+
step("extracting components", `${components.length} found`);
|
|
214906
|
+
step("mapping relations", `${relationCount} mapped`);
|
|
214907
|
+
const patternsLabel = `${actualGuards} guard${actualGuards !== 1 ? "s" : ""} \xB7 ${actualEndpoints} endpoints`;
|
|
214908
|
+
step("analyzing patterns", patternsLabel);
|
|
214909
|
+
const telemetry = scanResult.telemetry;
|
|
214910
|
+
if (telemetry) {
|
|
214911
|
+
console.log(` Scan: ${telemetry.duration_ms}ms \xB7 ${telemetry.memory_mb}MB \xB7 ${telemetry.files_parsed} files`);
|
|
214912
|
+
} else {
|
|
214913
|
+
console.log(` Scan: ${scanMs}ms`);
|
|
214789
214914
|
}
|
|
214915
|
+
console.log("");
|
|
214790
214916
|
let repo;
|
|
214791
214917
|
try {
|
|
214792
214918
|
const repos = await api.get(`/workspaces/${workspaceSlug}/repos`);
|
|
214793
214919
|
repo = Array.isArray(repos) ? repos.find((r) => r.github_org === remote.org && r.github_repo === remote.repo) : null;
|
|
214794
214920
|
} catch {
|
|
214795
214921
|
}
|
|
214796
|
-
if (repo) {
|
|
214797
|
-
console.log(`
|
|
214798
|
-
Repo: ${remote.repo} \u2713`);
|
|
214799
|
-
} else {
|
|
214922
|
+
if (!repo) {
|
|
214800
214923
|
try {
|
|
214801
214924
|
repo = await api.post(`/workspaces/${workspaceSlug}/repos`, {
|
|
214802
214925
|
github_org: remote.org,
|
|
214803
214926
|
github_repo: remote.repo
|
|
214804
214927
|
});
|
|
214805
|
-
console.log(` Repo: ${remote.repo} (connected)`);
|
|
214806
214928
|
} catch (err) {
|
|
214807
214929
|
console.error(` Failed to connect repo: ${err?.message || "unknown"}`);
|
|
214808
214930
|
process.exit(1);
|
|
@@ -214810,39 +214932,35 @@ async function initCommand(args) {
|
|
|
214810
214932
|
}
|
|
214811
214933
|
try {
|
|
214812
214934
|
await api.post(`/workspaces/${workspaceSlug}/repos/${repo.id}/baseline`, summary);
|
|
214813
|
-
|
|
214814
|
-
} catch
|
|
214815
|
-
|
|
214935
|
+
step("uploading baseline", "\u2713");
|
|
214936
|
+
} catch {
|
|
214937
|
+
step("uploading baseline", "failed (continuing)");
|
|
214816
214938
|
}
|
|
214817
214939
|
if (components.length > 0) {
|
|
214818
214940
|
try {
|
|
214819
214941
|
await api.post(`/workspaces/${workspaceSlug}/repos/${repo.id}/components`, { components });
|
|
214820
|
-
|
|
214821
|
-
} catch
|
|
214822
|
-
|
|
214942
|
+
step("uploading components", `${components.length} components \xB7 ${relationCount} relations \u2713`);
|
|
214943
|
+
} catch {
|
|
214944
|
+
step("uploading components", "failed (continuing)");
|
|
214823
214945
|
}
|
|
214824
214946
|
}
|
|
214825
|
-
console.log("\nAnalyzing code patterns...");
|
|
214826
214947
|
const patterns = earlyPatterns;
|
|
214827
214948
|
const smartRules = generateSmartRules(repo.id, patterns);
|
|
214828
|
-
console.log(` Detected: ${patterns.guardNames.length} guards, ${patterns.endpointPaths.length} endpoints`);
|
|
214829
|
-
if (patterns.hasMultiTenant) console.log(" Multi-tenant pattern detected");
|
|
214830
|
-
if (patterns.largeFiles.length > 0) console.log(` Large files: ${patterns.largeFiles.length} (quarantine candidates)`);
|
|
214831
|
-
if (patterns.quarantineCandidates.length > 0) console.log(` Legacy files: ${patterns.quarantineCandidates.length}`);
|
|
214832
|
-
console.log(`
|
|
214833
|
-
Creating ${smartRules.length} architectural rules...`);
|
|
214834
214949
|
let rulesCreated = 0;
|
|
214835
214950
|
let rulesSkipped = 0;
|
|
214836
214951
|
for (const rule of smartRules) {
|
|
214837
214952
|
try {
|
|
214838
|
-
await api.post(`/workspaces/${workspaceSlug}/rules`, { ...rule, auto_suggested: true });
|
|
214839
|
-
|
|
214953
|
+
const result = await api.post(`/workspaces/${workspaceSlug}/rules`, { ...rule, auto_suggested: true });
|
|
214954
|
+
if (result?.skipped) {
|
|
214955
|
+
rulesSkipped++;
|
|
214956
|
+
} else {
|
|
214957
|
+
rulesCreated++;
|
|
214958
|
+
}
|
|
214840
214959
|
} catch {
|
|
214841
214960
|
rulesSkipped++;
|
|
214842
214961
|
}
|
|
214843
214962
|
}
|
|
214844
|
-
|
|
214845
|
-
console.log("\nCreating context watchers from detected modules...");
|
|
214963
|
+
step("creating rules", `${rulesCreated} created \xB7 ${rulesSkipped} skipped \u2713`);
|
|
214846
214964
|
const smartWatchers = generateSmartWatchers(components);
|
|
214847
214965
|
let watchersCreated = 0;
|
|
214848
214966
|
let watchersSkipped = 0;
|
|
@@ -214860,19 +214978,17 @@ Creating ${smartRules.length} architectural rules...`);
|
|
|
214860
214978
|
created_by: "driftless-init"
|
|
214861
214979
|
});
|
|
214862
214980
|
watchersCreated++;
|
|
214863
|
-
console.log(` \u2713 ${watcher.name} \u2014 ${watcher.what}`);
|
|
214864
214981
|
} catch {
|
|
214865
214982
|
watchersSkipped++;
|
|
214866
214983
|
}
|
|
214867
214984
|
}
|
|
214868
|
-
|
|
214869
|
-
console.log("\nScanning for existing documentation...");
|
|
214985
|
+
step("creating context", `${watchersCreated} watchers \u2713`);
|
|
214870
214986
|
const existingDocs = detectExistingDocs(cwd);
|
|
214871
214987
|
let docsAnchored = 0;
|
|
214872
214988
|
for (const doc of existingDocs) {
|
|
214873
214989
|
try {
|
|
214874
|
-
const fullPath = (0,
|
|
214875
|
-
const fileContent = (0,
|
|
214990
|
+
const fullPath = (0, import_node_path4.resolve)(cwd, doc.path);
|
|
214991
|
+
const fileContent = (0, import_node_fs4.readFileSync)(fullPath, "utf-8");
|
|
214876
214992
|
await api.post(`/workspaces/${workspaceSlug}/watchers`, {
|
|
214877
214993
|
name: doc.name,
|
|
214878
214994
|
what: doc.what,
|
|
@@ -214885,21 +215001,31 @@ Creating ${smartRules.length} architectural rules...`);
|
|
|
214885
215001
|
created_by: "driftless-init"
|
|
214886
215002
|
});
|
|
214887
215003
|
docsAnchored++;
|
|
214888
|
-
console.log(` \u2713 ${doc.name} \u2014 ${doc.path}`);
|
|
214889
215004
|
} catch {
|
|
214890
215005
|
}
|
|
214891
215006
|
}
|
|
214892
|
-
|
|
214893
|
-
|
|
214894
|
-
|
|
214895
|
-
|
|
214896
|
-
|
|
214897
|
-
|
|
214898
|
-
|
|
214899
|
-
|
|
214900
|
-
|
|
214901
|
-
|
|
214902
|
-
console.log(
|
|
215007
|
+
step("anchoring docs", `${docsAnchored} docs \u2713`);
|
|
215008
|
+
let skillLine = "skipped";
|
|
215009
|
+
try {
|
|
215010
|
+
const skillResult = await runInstallSkill(cwd);
|
|
215011
|
+
const claudeIcon = skillResult.claudeMd === "created" ? "CLAUDE.md created" : skillResult.claudeMd === "updated" ? "CLAUDE.md updated" : "CLAUDE.md ok";
|
|
215012
|
+
const agentsIcon = skillResult.agentsMd === "created" ? "AGENTS.md created" : skillResult.agentsMd === "updated" ? "AGENTS.md updated" : "AGENTS.md ok";
|
|
215013
|
+
skillLine = `${claudeIcon} \xB7 ${agentsIcon} \u2713`;
|
|
215014
|
+
} catch {
|
|
215015
|
+
}
|
|
215016
|
+
step("installing skill", skillLine);
|
|
215017
|
+
console.log("");
|
|
215018
|
+
console.log("\u2713 repo context bootstrapped");
|
|
215019
|
+
console.log(` \u251C\u2500 watchers ${watchersCreated}`);
|
|
215020
|
+
console.log(` \u251C\u2500 rules ${rulesCreated}`);
|
|
215021
|
+
console.log(` \u251C\u2500 docs ${docsAnchored}`);
|
|
215022
|
+
console.log(` \u251C\u2500 components ${components.length}`);
|
|
215023
|
+
console.log(` \u2514\u2500 relations ${relationCount}`);
|
|
215024
|
+
console.log("");
|
|
215025
|
+
console.log(" dashboard \u2192 driftless.icu/ecosystem");
|
|
215026
|
+
console.log(" next \u2192 driftless context list");
|
|
215027
|
+
console.log("");
|
|
215028
|
+
console.log(DIVIDER);
|
|
214903
215029
|
}
|
|
214904
215030
|
|
|
214905
215031
|
// src/commands/scan.ts
|
|
@@ -215015,8 +215141,8 @@ ${result.violations.length} violation(s) found (${rulesEvaluated} rule(s) evalua
|
|
|
215015
215141
|
|
|
215016
215142
|
// src/commands/context.ts
|
|
215017
215143
|
init_git();
|
|
215018
|
-
var
|
|
215019
|
-
var
|
|
215144
|
+
var import_node_fs5 = require("node:fs");
|
|
215145
|
+
var import_node_path5 = require("node:path");
|
|
215020
215146
|
function parseArgs(args) {
|
|
215021
215147
|
const flags = {};
|
|
215022
215148
|
const positional = [];
|
|
@@ -215250,7 +215376,7 @@ async function contextCommand(args) {
|
|
|
215250
215376
|
}
|
|
215251
215377
|
process.exit(0);
|
|
215252
215378
|
}
|
|
215253
|
-
const missingFiles = files.filter((f) => !(0,
|
|
215379
|
+
const missingFiles = files.filter((f) => !(0, import_node_fs5.existsSync)((0, import_node_path5.resolve)(process.cwd(), f)));
|
|
215254
215380
|
if (missingFiles.length > 0 && !isJSON) {
|
|
215255
215381
|
console.error(`File(s) not found locally: ${missingFiles.join(", ")}. Matching by pattern only.`);
|
|
215256
215382
|
}
|
|
@@ -215329,7 +215455,7 @@ async function contextCommand(args) {
|
|
|
215329
215455
|
let fileContent;
|
|
215330
215456
|
if (flags["file"]) {
|
|
215331
215457
|
try {
|
|
215332
|
-
fileContent = (0,
|
|
215458
|
+
fileContent = (0, import_node_fs5.readFileSync)(flags["file"], "utf-8");
|
|
215333
215459
|
} catch {
|
|
215334
215460
|
console.error(`File not found: ${flags["file"]}`);
|
|
215335
215461
|
process.exit(1);
|
|
@@ -215494,7 +215620,7 @@ async function contextCommand(args) {
|
|
|
215494
215620
|
let fileContent;
|
|
215495
215621
|
if (docFlag) {
|
|
215496
215622
|
try {
|
|
215497
|
-
fileContent = (0,
|
|
215623
|
+
fileContent = (0, import_node_fs5.readFileSync)(docFlag, "utf-8");
|
|
215498
215624
|
} catch {
|
|
215499
215625
|
console.error(`File not found: ${docFlag}`);
|
|
215500
215626
|
process.exit(1);
|
|
@@ -215556,7 +215682,7 @@ async function contextCommand(args) {
|
|
|
215556
215682
|
console.error("No files provided.");
|
|
215557
215683
|
process.exit(1);
|
|
215558
215684
|
}
|
|
215559
|
-
const missingFiles = files.filter((f) => !(0,
|
|
215685
|
+
const missingFiles = files.filter((f) => !(0, import_node_fs5.existsSync)((0, import_node_path5.resolve)(process.cwd(), f)));
|
|
215560
215686
|
if (missingFiles.length > 0 && !isJSON) {
|
|
215561
215687
|
console.error(`File(s) not found locally: ${missingFiles.join(", ")}. Matching by pattern only.`);
|
|
215562
215688
|
}
|
|
@@ -215601,14 +215727,21 @@ Warnings:`);
|
|
|
215601
215727
|
emitJSON2(results);
|
|
215602
215728
|
} else {
|
|
215603
215729
|
if (results.length > 0) {
|
|
215604
|
-
console.log(`Matched ${results.length} topic${results.length === 1 ? "" : "s"}
|
|
215730
|
+
console.log(`Matched ${results.length} context topic${results.length === 1 ? "" : "s"} for ${files.length} file${files.length === 1 ? "" : "s"}:
|
|
215731
|
+
`);
|
|
215605
215732
|
for (const r of results) {
|
|
215606
|
-
|
|
215733
|
+
try {
|
|
215734
|
+
const fullCtx = await api.get(`/workspaces/${workspaceSlug}/watchers/${r.context.topic}`);
|
|
215735
|
+
renderContextHuman(fullCtx);
|
|
215736
|
+
console.log("");
|
|
215737
|
+
} catch {
|
|
215738
|
+
console.log(`\u258C ${r.context.topic} (${r.match_reason})`);
|
|
215739
|
+
console.log(` ${r.context.summary}`);
|
|
215740
|
+
console.log("");
|
|
215741
|
+
}
|
|
215607
215742
|
}
|
|
215608
|
-
console.log(`
|
|
215609
|
-
Context delivered for ${files.length} file${files.length === 1 ? "" : "s"}.`);
|
|
215610
215743
|
} else {
|
|
215611
|
-
console.log(`No context topics match these files. No
|
|
215744
|
+
console.log(`No context topics match these files. No context covers the changed paths.`);
|
|
215612
215745
|
}
|
|
215613
215746
|
}
|
|
215614
215747
|
} catch (e) {
|
|
@@ -215619,10 +215752,10 @@ Context delivered for ${files.length} file${files.length === 1 ? "" : "s"}.`);
|
|
|
215619
215752
|
}
|
|
215620
215753
|
if (subCommand === "export") {
|
|
215621
215754
|
const dir = flags["dir"] ?? ".driftless/watchers";
|
|
215622
|
-
const absDir = (0,
|
|
215755
|
+
const absDir = (0, import_node_path5.resolve)(process.cwd(), dir);
|
|
215623
215756
|
try {
|
|
215624
215757
|
const summaries = await api.get(`/workspaces/${workspaceSlug}/watchers`);
|
|
215625
|
-
(0,
|
|
215758
|
+
(0, import_node_fs5.mkdirSync)(absDir, { recursive: true });
|
|
215626
215759
|
for (const summary of summaries) {
|
|
215627
215760
|
const slug = summary.topic;
|
|
215628
215761
|
let ctx;
|
|
@@ -215652,10 +215785,10 @@ Context delivered for ${files.length} file${files.length === 1 ? "" : "s"}.`);
|
|
|
215652
215785
|
}
|
|
215653
215786
|
if (ctx.description.ownership) lines.push(`ownership: ${safeStr(ctx.description.ownership)}`);
|
|
215654
215787
|
const yamlContent = lines.join("\n") + "\n";
|
|
215655
|
-
(0,
|
|
215788
|
+
(0, import_node_fs5.writeFileSync)((0, import_node_path5.join)(absDir, `${slug}.yaml`), yamlContent, "utf-8");
|
|
215656
215789
|
}
|
|
215657
215790
|
if (!isJSON) {
|
|
215658
|
-
console.log(`Exported ${summaries.length}
|
|
215791
|
+
console.log(`Exported ${summaries.length} context topic${summaries.length === 1 ? "" : "s"} \u2192 ${dir}/`);
|
|
215659
215792
|
} else {
|
|
215660
215793
|
emitJSON2({ exported: summaries.length, dir });
|
|
215661
215794
|
}
|
|
@@ -215667,14 +215800,14 @@ Context delivered for ${files.length} file${files.length === 1 ? "" : "s"}.`);
|
|
|
215667
215800
|
}
|
|
215668
215801
|
if (subCommand === "import") {
|
|
215669
215802
|
const dir = flags["dir"] ?? ".driftless/watchers";
|
|
215670
|
-
const absDir = (0,
|
|
215671
|
-
if (!(0,
|
|
215803
|
+
const absDir = (0, import_node_path5.resolve)(process.cwd(), dir);
|
|
215804
|
+
if (!(0, import_node_fs5.existsSync)(absDir)) {
|
|
215672
215805
|
console.error(`Directory not found: ${dir}`);
|
|
215673
215806
|
process.exit(1);
|
|
215674
215807
|
}
|
|
215675
215808
|
let files;
|
|
215676
215809
|
try {
|
|
215677
|
-
files = (0,
|
|
215810
|
+
files = (0, import_node_fs5.readdirSync)(absDir).filter((f) => f.endsWith(".yaml"));
|
|
215678
215811
|
} catch (e) {
|
|
215679
215812
|
console.error(`Failed to read directory: ${formatError(e)}`);
|
|
215680
215813
|
process.exit(1);
|
|
@@ -215686,10 +215819,10 @@ Context delivered for ${files.length} file${files.length === 1 ? "" : "s"}.`);
|
|
|
215686
215819
|
let created = 0;
|
|
215687
215820
|
let updated = 0;
|
|
215688
215821
|
for (const file of files) {
|
|
215689
|
-
const filePath = (0,
|
|
215822
|
+
const filePath = (0, import_node_path5.join)(absDir, file);
|
|
215690
215823
|
let raw;
|
|
215691
215824
|
try {
|
|
215692
|
-
raw = (0,
|
|
215825
|
+
raw = (0, import_node_fs5.readFileSync)(filePath, "utf-8");
|
|
215693
215826
|
} catch {
|
|
215694
215827
|
console.error(` skipped ${file} (read error)`);
|
|
215695
215828
|
continue;
|
|
@@ -215775,8 +215908,8 @@ Run 'driftless help context' for full reference.`);
|
|
|
215775
215908
|
|
|
215776
215909
|
// src/commands/session.ts
|
|
215777
215910
|
init_git();
|
|
215778
|
-
var
|
|
215779
|
-
var
|
|
215911
|
+
var import_node_fs6 = require("node:fs");
|
|
215912
|
+
var import_node_path6 = require("node:path");
|
|
215780
215913
|
function parseArgs2(args) {
|
|
215781
215914
|
const flags = {};
|
|
215782
215915
|
const positional = [];
|
|
@@ -215838,7 +215971,7 @@ async function sessionCommand(args) {
|
|
|
215838
215971
|
}
|
|
215839
215972
|
process.exit(0);
|
|
215840
215973
|
}
|
|
215841
|
-
const missingFiles = files.filter((f) => !(0,
|
|
215974
|
+
const missingFiles = files.filter((f) => !(0, import_node_fs6.existsSync)((0, import_node_path6.resolve)(process.cwd(), f)));
|
|
215842
215975
|
if (missingFiles.length > 0 && !isJSON) {
|
|
215843
215976
|
console.error(`Warning: ${missingFiles.length} file(s) not found locally \u2014 matching by pattern only.`);
|
|
215844
215977
|
}
|
|
@@ -215887,7 +216020,7 @@ async function sessionCommand(args) {
|
|
|
215887
216020
|
console.log(`Session started for ${files.length} file(s):
|
|
215888
216021
|
`);
|
|
215889
216022
|
for (const f of files) {
|
|
215890
|
-
const exists = (0,
|
|
216023
|
+
const exists = (0, import_node_fs6.existsSync)((0, import_node_path6.resolve)(process.cwd(), f));
|
|
215891
216024
|
console.log(` ${exists ? "\u2713" : "\u2717"} ${f}`);
|
|
215892
216025
|
}
|
|
215893
216026
|
if (missingFiles.length > 0) {
|
|
@@ -215956,9 +216089,9 @@ Rules that will be evaluated:`);
|
|
|
215956
216089
|
console.error(`Repo '${remote.repo}' not found. Run 'driftless init' first.`);
|
|
215957
216090
|
process.exit(1);
|
|
215958
216091
|
}
|
|
215959
|
-
const { getUncommittedDiff:
|
|
216092
|
+
const { getUncommittedDiff: getUncommittedDiff2, getStagedDiff: getStagedDiff2, getLastCommitHash: getLastCommitHash2, getAuthorName: getAuthorName2 } = await Promise.resolve().then(() => (init_git(), git_exports));
|
|
215960
216093
|
const staged = getStagedDiff2();
|
|
215961
|
-
const unstaged =
|
|
216094
|
+
const unstaged = getUncommittedDiff2();
|
|
215962
216095
|
const diff = [staged, unstaged].filter(Boolean).join("\n");
|
|
215963
216096
|
if (!diff && !isJSON) {
|
|
215964
216097
|
console.log("No changes to scan. Session clean.");
|
|
@@ -216048,149 +216181,6 @@ Examples:
|
|
|
216048
216181
|
driftless session finish # scan + context report`);
|
|
216049
216182
|
}
|
|
216050
216183
|
|
|
216051
|
-
// src/commands/install-skill.ts
|
|
216052
|
-
var import_node_fs6 = require("node:fs");
|
|
216053
|
-
var import_node_path6 = require("node:path");
|
|
216054
|
-
var template = `# Driftless \u2014 Live Repo Context
|
|
216055
|
-
|
|
216056
|
-
Driftless Cloud holds the team's living codebase context (topics, anchors, rules, gotchas).
|
|
216057
|
-
This file teaches you how to use it. Treat it as part of the toolchain, not documentation.
|
|
216058
|
-
|
|
216059
|
-
## Agent loop
|
|
216060
|
-
|
|
216061
|
-
### 1. Before editing \u2014 pull context
|
|
216062
|
-
|
|
216063
|
-
If you know the topic:
|
|
216064
|
-
|
|
216065
|
-
\`\`\`bash
|
|
216066
|
-
driftless context get <topic>
|
|
216067
|
-
\`\`\`
|
|
216068
|
-
|
|
216069
|
-
If you don't know which topic applies, discover it:
|
|
216070
|
-
|
|
216071
|
-
\`\`\`bash
|
|
216072
|
-
driftless context search "<keyword>"
|
|
216073
|
-
driftless context list
|
|
216074
|
-
\`\`\`
|
|
216075
|
-
|
|
216076
|
-
The \`get\` response is a canonical JSON object:
|
|
216077
|
-
|
|
216078
|
-
\`\`\`json
|
|
216079
|
-
{
|
|
216080
|
-
"topic": "<slug>",
|
|
216081
|
-
"summary": "...",
|
|
216082
|
-
"description": {
|
|
216083
|
-
"what": "...",
|
|
216084
|
-
"how": "...",
|
|
216085
|
-
"decisions": "...",
|
|
216086
|
-
"gotchas": [],
|
|
216087
|
-
"ownership": "..."
|
|
216088
|
-
},
|
|
216089
|
-
"anchors": {
|
|
216090
|
-
"files": [],
|
|
216091
|
-
"patterns": [],
|
|
216092
|
-
"repos": [],
|
|
216093
|
-
"docs": []
|
|
216094
|
-
},
|
|
216095
|
-
"components": [],
|
|
216096
|
-
"rules": [],
|
|
216097
|
-
"invariants": [],
|
|
216098
|
-
"violations": [],
|
|
216099
|
-
"events": [],
|
|
216100
|
-
"required_checks": [],
|
|
216101
|
-
"stale": { "is_stale": false, "reason": null },
|
|
216102
|
-
"metadata": { "created_by": "...", "last_updated": "...", "source": "manual|auto|doc|agent" }
|
|
216103
|
-
}
|
|
216104
|
-
\`\`\`
|
|
216105
|
-
|
|
216106
|
-
Always read:
|
|
216107
|
-
- \`description.what\` and \`description.how\` \u2014 what you're about to touch
|
|
216108
|
-
- \`description.decisions\` \u2014 why it's built this way
|
|
216109
|
-
- \`description.gotchas\` \u2014 known traps
|
|
216110
|
-
- \`anchors.docs\` \u2014 anchored team docs
|
|
216111
|
-
- \`stale.is_stale\` \u2014 if true, the context may be outdated; read \`stale.reason\`
|
|
216112
|
-
|
|
216113
|
-
Note: \`rules\`, \`invariants\`, \`violations\`, \`events\`, and \`required_checks\` may be empty
|
|
216114
|
-
during PR 1; they get populated in subsequent releases. Other fields are authoritative.
|
|
216115
|
-
|
|
216116
|
-
### 2. During work
|
|
216117
|
-
|
|
216118
|
-
Respect what the topic tells you. Follow decisions and gotchas. If anchored docs contradict
|
|
216119
|
-
code, the docs are usually intent \u2014 verify before changing.
|
|
216120
|
-
|
|
216121
|
-
### 3. Before finishing \u2014 scan
|
|
216122
|
-
|
|
216123
|
-
\`\`\`bash
|
|
216124
|
-
driftless scan --diff
|
|
216125
|
-
\`\`\`
|
|
216126
|
-
|
|
216127
|
-
This evaluates your uncommitted changes against active Cloud rules. Exit code:
|
|
216128
|
-
- \`0\` \u2014 clean
|
|
216129
|
-
- \`1\` \u2014 violations (read each \`explanation\`, fix, re-scan until clean)
|
|
216130
|
-
|
|
216131
|
-
Do not push if scan returns violations.
|
|
216132
|
-
|
|
216133
|
-
### 4. After learning \u2014 write context back
|
|
216134
|
-
|
|
216135
|
-
If you discovered something durable about the codebase, write it back so the next session benefits:
|
|
216136
|
-
|
|
216137
|
-
Update an existing topic:
|
|
216138
|
-
|
|
216139
|
-
\`\`\`bash
|
|
216140
|
-
driftless context update <topic> \\
|
|
216141
|
-
--gotchas "Setting X to Y breaks Z under condition W"
|
|
216142
|
-
\`\`\`
|
|
216143
|
-
|
|
216144
|
-
Or add a new topic:
|
|
216145
|
-
|
|
216146
|
-
\`\`\`bash
|
|
216147
|
-
driftless context add "<name>" \\
|
|
216148
|
-
--what "What this piece is" \\
|
|
216149
|
-
--how "How it works" \\
|
|
216150
|
-
--pattern "src/path/**" \\
|
|
216151
|
-
--decisions "Why built this way" \\
|
|
216152
|
-
--gotchas "Known traps" \\
|
|
216153
|
-
--ownership "@team"
|
|
216154
|
-
\`\`\`
|
|
216155
|
-
|
|
216156
|
-
Field reference:
|
|
216157
|
-
- \`--what\`, \`--how\`, \`--decisions\`, \`--gotchas\`, \`--ownership\`
|
|
216158
|
-
- \`--pattern\` (glob) or \`--where\` (explicit path) \u2014 mutually exclusive
|
|
216159
|
-
- \`--file <path>\` (on \`add\`) \u2014 anchor an existing markdown doc
|
|
216160
|
-
|
|
216161
|
-
## Output format
|
|
216162
|
-
|
|
216163
|
-
All CLI commands output JSON by default for agent consumption. Use \`--human\` for readable text.
|
|
216164
|
-
|
|
216165
|
-
## What Driftless is
|
|
216166
|
-
|
|
216167
|
-
Living context infrastructure for coding agents. CLI is the daily interface; the dashboard
|
|
216168
|
-
is observability for humans, not where agents work.
|
|
216169
|
-
|
|
216170
|
-
## What Driftless is not
|
|
216171
|
-
|
|
216172
|
-
Does not modify code. Does not approve or reject PRs. Does not block merges. Is not CI.
|
|
216173
|
-
Is not an AI reviewer.
|
|
216174
|
-
|
|
216175
|
-
Context delivery + structural verification only.
|
|
216176
|
-
`;
|
|
216177
|
-
function installSkillCommand() {
|
|
216178
|
-
const cwd = process.cwd();
|
|
216179
|
-
const agentsPath = (0, import_node_path6.resolve)(cwd, "AGENTS.md");
|
|
216180
|
-
if ((0, import_node_fs6.existsSync)(agentsPath)) {
|
|
216181
|
-
const existing = (0, import_node_fs6.readFileSync)(agentsPath, "utf8");
|
|
216182
|
-
if (existing.includes("# Driftless")) {
|
|
216183
|
-
console.log("Driftless section already present in AGENTS.md.");
|
|
216184
|
-
return;
|
|
216185
|
-
}
|
|
216186
|
-
(0, import_node_fs6.writeFileSync)(agentsPath, existing + "\n---\n\n" + template);
|
|
216187
|
-
console.log(`Appended Driftless section to ${agentsPath}`);
|
|
216188
|
-
} else {
|
|
216189
|
-
(0, import_node_fs6.writeFileSync)(agentsPath, template);
|
|
216190
|
-
console.log(`Driftless skill installed at ${agentsPath}`);
|
|
216191
|
-
}
|
|
216192
|
-
}
|
|
216193
|
-
|
|
216194
216184
|
// src/commands/login.ts
|
|
216195
216185
|
var import_node_fs7 = require("node:fs");
|
|
216196
216186
|
var import_node_path7 = require("node:path");
|
|
@@ -216408,7 +216398,7 @@ function pad2(s, n) {
|
|
|
216408
216398
|
}
|
|
216409
216399
|
|
|
216410
216400
|
// src/index.ts
|
|
216411
|
-
var VERSION = "0.1.
|
|
216401
|
+
var VERSION = "0.1.26";
|
|
216412
216402
|
var HELP_TEXT = `Driftless CLI v${VERSION} \u2014 Living repo context for humans and coding agents
|
|
216413
216403
|
|
|
216414
216404
|
Install: npm install -g @driftless-sh/cli
|
|
@@ -216628,7 +216618,7 @@ async function main() {
|
|
|
216628
216618
|
await sessionCommand(args.slice(1));
|
|
216629
216619
|
break;
|
|
216630
216620
|
case "install-skill":
|
|
216631
|
-
installSkillCommand();
|
|
216621
|
+
await installSkillCommand();
|
|
216632
216622
|
break;
|
|
216633
216623
|
case "login":
|
|
216634
216624
|
loginCommand(args.slice(1));
|