@driftless-sh/cli 0.1.33 → 0.1.35

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 CHANGED
@@ -6,9 +6,16 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
9
12
  var __commonJS = (cb, mod) => function __require() {
10
13
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
11
14
  };
15
+ var __export = (target, all) => {
16
+ for (var name in all)
17
+ __defProp(target, name, { get: all[name], enumerable: true });
18
+ };
12
19
  var __copyProps = (to, from, except, desc) => {
13
20
  if (from && typeof from === "object" || typeof from === "function") {
14
21
  for (let key of __getOwnPropNames(from))
@@ -26,6 +33,136 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
33
  mod
27
34
  ));
28
35
 
36
+ // src/api-client.ts
37
+ var api_client_exports = {};
38
+ __export(api_client_exports, {
39
+ api: () => api,
40
+ formatError: () => formatError,
41
+ getApiKey: () => getApiKey,
42
+ getApiUrl: () => getApiUrl
43
+ });
44
+ function loadApiKey() {
45
+ const envKey = process.env["DRIFTLESS_API_KEY"];
46
+ if (envKey) return envKey;
47
+ try {
48
+ if ((0, import_node_fs.existsSync)(CONFIG_PATH)) {
49
+ const config = JSON.parse((0, import_node_fs.readFileSync)(CONFIG_PATH, "utf8"));
50
+ return config.api_key || null;
51
+ }
52
+ } catch {
53
+ }
54
+ return null;
55
+ }
56
+ function getBaseUrl() {
57
+ const envUrl = process.env["DRIFTLESS_API_URL"];
58
+ if (envUrl) {
59
+ return envUrl.endsWith("/api/v1") ? envUrl : `${envUrl}/api/v1`;
60
+ }
61
+ try {
62
+ if ((0, import_node_fs.existsSync)(CONFIG_PATH)) {
63
+ const config = JSON.parse((0, import_node_fs.readFileSync)(CONFIG_PATH, "utf8"));
64
+ return config.api_url || DEFAULT_URL;
65
+ }
66
+ } catch {
67
+ }
68
+ return DEFAULT_URL;
69
+ }
70
+ function parseError(e) {
71
+ const msg = e.message;
72
+ const jsonMatch = msg.match(/\{[\s\S]*\}/);
73
+ if (jsonMatch) {
74
+ try {
75
+ const parsed = JSON.parse(jsonMatch[0]);
76
+ const parts = [];
77
+ if (parsed.message) parts.push(parsed.message);
78
+ if (parsed.request_id) parts.push(`request_id: ${parsed.request_id}`);
79
+ if (parsed.retryable !== void 0) parts.push(`retryable: ${parsed.retryable ? "yes" : "no"}`);
80
+ if (parsed.endpoint) parts.push(`endpoint: ${parsed.endpoint}`);
81
+ if (parts.length > 0) return parts.join(" | ");
82
+ } catch {
83
+ }
84
+ }
85
+ const statusMatch = msg.match(/HTTP (\d+):/);
86
+ if (statusMatch) {
87
+ const code = parseInt(statusMatch[1], 10);
88
+ if (code === 500) return "Internal server error \u2014 the API encountered an unexpected issue";
89
+ if (code === 401) return "Authentication failed \u2014 check your API key";
90
+ if (code === 403) return "Access denied \u2014 your API key lacks permission";
91
+ if (code === 404) return "Not found \u2014 the resource does not exist";
92
+ if (code === 429) return "Rate limited \u2014 too many requests, try again later";
93
+ return `Server error (HTTP ${code})`;
94
+ }
95
+ return msg;
96
+ }
97
+ function request(method, path, body) {
98
+ return new Promise((resolve8, reject) => {
99
+ const baseUrl = getBaseUrl();
100
+ const fullUrl = `${baseUrl}${path}`;
101
+ const url = new URL(fullUrl);
102
+ const isHttps = url.protocol === "https:";
103
+ const fn = isHttps ? import_node_https.request : import_node_http.request;
104
+ const headers = {
105
+ "Content-Type": "application/json",
106
+ Accept: "application/json"
107
+ };
108
+ const apiKey = loadApiKey();
109
+ if (apiKey) {
110
+ headers["X-API-Key"] = apiKey;
111
+ }
112
+ const req = fn(
113
+ fullUrl,
114
+ { method, headers },
115
+ (res) => {
116
+ let data = "";
117
+ res.on("data", (chunk) => data += chunk.toString());
118
+ res.on("end", () => {
119
+ if (res.statusCode && res.statusCode >= 400) {
120
+ reject(new Error(`HTTP ${res.statusCode}: ${data}`));
121
+ return;
122
+ }
123
+ try {
124
+ resolve8(JSON.parse(data));
125
+ } catch {
126
+ resolve8(data);
127
+ }
128
+ });
129
+ }
130
+ );
131
+ req.on("error", (e) => reject(new Error(`Connection failed: ${e.message}`)));
132
+ if (body) req.write(JSON.stringify(body));
133
+ req.end();
134
+ });
135
+ }
136
+ function getApiUrl() {
137
+ return getBaseUrl();
138
+ }
139
+ function getApiKey() {
140
+ return loadApiKey();
141
+ }
142
+ function formatError(e) {
143
+ return parseError(e);
144
+ }
145
+ var import_node_http, import_node_https, import_node_fs, import_node_path, import_node_os, CONFIG_PATH, DEFAULT_URL, api;
146
+ var init_api_client = __esm({
147
+ "src/api-client.ts"() {
148
+ "use strict";
149
+ import_node_http = require("node:http");
150
+ import_node_https = require("node:https");
151
+ import_node_fs = require("node:fs");
152
+ import_node_path = require("node:path");
153
+ import_node_os = require("node:os");
154
+ CONFIG_PATH = (0, import_node_path.resolve)((0, import_node_os.homedir)(), ".driftless", "config.json");
155
+ DEFAULT_URL = "http://localhost:3000/api/v1";
156
+ api = {
157
+ get: (path) => request("GET", path),
158
+ post: (path, body) => request("POST", path, body),
159
+ put: (path, body) => request("PUT", path, body),
160
+ patch: (path, body) => request("PATCH", path, body),
161
+ delete: (path) => request("DELETE", path)
162
+ };
163
+ }
164
+ });
165
+
29
166
  // ../../libs/scanner/dist/identity/identity.js
30
167
  var require_identity = __commonJS({
31
168
  "../../libs/scanner/dist/identity/identity.js"(exports2) {
@@ -2436,7 +2573,7 @@ var require_typescript = __commonJS({
2436
2573
  var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
2437
2574
  var __getOwnPropNames2 = Object.getOwnPropertyNames;
2438
2575
  var __hasOwnProp2 = Object.prototype.hasOwnProperty;
2439
- var __export = (target, all) => {
2576
+ var __export2 = (target, all) => {
2440
2577
  for (var name in all)
2441
2578
  __defProp2(target, name, { get: all[name], enumerable: true });
2442
2579
  };
@@ -2450,7 +2587,7 @@ var require_typescript = __commonJS({
2450
2587
  };
2451
2588
  var __toCommonJS = (mod) => (__copyProps2, mod);
2452
2589
  var typescript_exports = {};
2453
- __export(typescript_exports, {
2590
+ __export2(typescript_exports, {
2454
2591
  ANONYMOUS: () => ANONYMOUS,
2455
2592
  AccessFlags: () => AccessFlags,
2456
2593
  AssertionLevel: () => AssertionLevel,
@@ -7537,7 +7674,7 @@ ${lanes.join("\n")}
7537
7674
  }
7538
7675
  var timestamp = nativePerformanceTime ? () => nativePerformanceTime.now() : Date.now;
7539
7676
  var ts_performance_exports = {};
7540
- __export(ts_performance_exports, {
7677
+ __export2(ts_performance_exports, {
7541
7678
  clearMarks: () => clearMarks,
7542
7679
  clearMeasures: () => clearMeasures,
7543
7680
  createTimer: () => createTimer,
@@ -55840,7 +55977,7 @@ ${lanes.join("\n")}
55840
55977
  }
55841
55978
  }
55842
55979
  var ts_moduleSpecifiers_exports = {};
55843
- __export(ts_moduleSpecifiers_exports, {
55980
+ __export2(ts_moduleSpecifiers_exports, {
55844
55981
  RelativePreference: () => RelativePreference,
55845
55982
  countPathComponents: () => countPathComponents,
55846
55983
  forEachFileNameOfModule: () => forEachFileNameOfModule,
@@ -150640,7 +150777,7 @@ ${lanes.join("\n")}
150640
150777
  }
150641
150778
  }
150642
150779
  var ts_JsTyping_exports = {};
150643
- __export(ts_JsTyping_exports, {
150780
+ __export2(ts_JsTyping_exports, {
150644
150781
  NameValidationResult: () => NameValidationResult,
150645
150782
  discoverTypings: () => discoverTypings,
150646
150783
  isTypingUpToDate: () => isTypingUpToDate,
@@ -157686,7 +157823,7 @@ interface Symbol {
157686
157823
  return options;
157687
157824
  }
157688
157825
  var ts_NavigateTo_exports = {};
157689
- __export(ts_NavigateTo_exports, {
157826
+ __export2(ts_NavigateTo_exports, {
157690
157827
  getNavigateToItems: () => getNavigateToItems
157691
157828
  });
157692
157829
  function getNavigateToItems(sourceFiles, checker, cancellationToken, searchValue, maxResultCount, excludeDtsFiles, excludeLibFiles) {
@@ -157791,7 +157928,7 @@ interface Symbol {
157791
157928
  };
157792
157929
  }
157793
157930
  var ts_NavigationBar_exports = {};
157794
- __export(ts_NavigationBar_exports, {
157931
+ __export2(ts_NavigationBar_exports, {
157795
157932
  getNavigationBarItems: () => getNavigationBarItems,
157796
157933
  getNavigationTree: () => getNavigationTree
157797
157934
  });
@@ -158579,7 +158716,7 @@ interface Symbol {
158579
158716
  return text.replace(/\\?(?:\r?\n|[\r\u2028\u2029])/g, "");
158580
158717
  }
158581
158718
  var ts_refactor_exports = {};
158582
- __export(ts_refactor_exports, {
158719
+ __export2(ts_refactor_exports, {
158583
158720
  addExportsInOldFile: () => addExportsInOldFile,
158584
158721
  addImportsForMovedSymbols: () => addImportsForMovedSymbols,
158585
158722
  addNewFileToTsconfig: () => addNewFileToTsconfig,
@@ -162122,7 +162259,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
162122
162259
  }
162123
162260
  }
162124
162261
  var ts_refactor_extractSymbol_exports = {};
162125
- __export(ts_refactor_extractSymbol_exports, {
162262
+ __export2(ts_refactor_extractSymbol_exports, {
162126
162263
  Messages: () => Messages,
162127
162264
  RangeFacts: () => RangeFacts,
162128
162265
  getRangeToExtract: () => getRangeToExtract2,
@@ -166701,7 +166838,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
166701
166838
  return result;
166702
166839
  }
166703
166840
  var ts_BreakpointResolver_exports = {};
166704
- __export(ts_BreakpointResolver_exports, {
166841
+ __export2(ts_BreakpointResolver_exports, {
166705
166842
  spanInSourceFileAtLocation: () => spanInSourceFileAtLocation
166706
166843
  });
166707
166844
  function spanInSourceFileAtLocation(sourceFile, position) {
@@ -167207,7 +167344,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
167207
167344
  }
167208
167345
  }
167209
167346
  var ts_CallHierarchy_exports = {};
167210
- __export(ts_CallHierarchy_exports, {
167347
+ __export2(ts_CallHierarchy_exports, {
167211
167348
  createCallHierarchyItem: () => createCallHierarchyItem,
167212
167349
  getIncomingCalls: () => getIncomingCalls,
167213
167350
  getOutgoingCalls: () => getOutgoingCalls,
@@ -167656,11 +167793,11 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
167656
167793
  return group(collectCallSites(program, declaration), getCallSiteGroupKey, (entries) => convertCallSiteGroupToOutgoingCall(program, entries));
167657
167794
  }
167658
167795
  var ts_classifier_exports = {};
167659
- __export(ts_classifier_exports, {
167796
+ __export2(ts_classifier_exports, {
167660
167797
  v2020: () => ts_classifier_v2020_exports
167661
167798
  });
167662
167799
  var ts_classifier_v2020_exports = {};
167663
- __export(ts_classifier_v2020_exports, {
167800
+ __export2(ts_classifier_v2020_exports, {
167664
167801
  TokenEncodingConsts: () => TokenEncodingConsts,
167665
167802
  TokenModifier: () => TokenModifier,
167666
167803
  TokenType: () => TokenType,
@@ -167668,7 +167805,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
167668
167805
  getSemanticClassifications: () => getSemanticClassifications2
167669
167806
  });
167670
167807
  var ts_codefix_exports = {};
167671
- __export(ts_codefix_exports, {
167808
+ __export2(ts_codefix_exports, {
167672
167809
  PreserveOptionalFlags: () => PreserveOptionalFlags,
167673
167810
  addNewNodeForMemberSymbol: () => addNewNodeForMemberSymbol,
167674
167811
  codeFixAll: () => codeFixAll,
@@ -179589,7 +179726,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
179589
179726
  }
179590
179727
  }
179591
179728
  var ts_Completions_exports = {};
179592
- __export(ts_Completions_exports, {
179729
+ __export2(ts_Completions_exports, {
179593
179730
  CompletionKind: () => CompletionKind,
179594
179731
  CompletionSource: () => CompletionSource,
179595
179732
  SortText: () => SortText,
@@ -183845,7 +183982,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
183845
183982
  return keyword === "abstract" || keyword === "async" || keyword === "await" || keyword === "declare" || keyword === "module" || keyword === "namespace" || keyword === "type" || keyword === "satisfies" || keyword === "as";
183846
183983
  }
183847
183984
  var ts_Completions_StringCompletions_exports = {};
183848
- __export(ts_Completions_StringCompletions_exports, {
183985
+ __export2(ts_Completions_StringCompletions_exports, {
183849
183986
  getStringLiteralCompletionDetails: () => getStringLiteralCompletionDetails,
183850
183987
  getStringLiteralCompletions: () => getStringLiteralCompletions
183851
183988
  });
@@ -184913,7 +185050,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
184913
185050
  return isCallExpression(node.parent) && firstOrUndefined(node.parent.arguments) === node && isIdentifier(node.parent.expression) && node.parent.expression.escapedText === "require";
184914
185051
  }
184915
185052
  var ts_FindAllReferences_exports = {};
184916
- __export(ts_FindAllReferences_exports, {
185053
+ __export2(ts_FindAllReferences_exports, {
184917
185054
  Core: () => Core,
184918
185055
  DefinitionKind: () => DefinitionKind,
184919
185056
  EntryKind: () => EntryKind,
@@ -187497,7 +187634,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
187497
187634
  }
187498
187635
  })(Core || (Core = {}));
187499
187636
  var ts_GoToDefinition_exports = {};
187500
- __export(ts_GoToDefinition_exports, {
187637
+ __export2(ts_GoToDefinition_exports, {
187501
187638
  createDefinitionInfo: () => createDefinitionInfo,
187502
187639
  getDefinitionAndBoundSpan: () => getDefinitionAndBoundSpan,
187503
187640
  getDefinitionAtPosition: () => getDefinitionAtPosition,
@@ -188069,7 +188206,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
188069
188206
  }
188070
188207
  }
188071
188208
  var ts_InlayHints_exports = {};
188072
- __export(ts_InlayHints_exports, {
188209
+ __export2(ts_InlayHints_exports, {
188073
188210
  provideInlayHints: () => provideInlayHints
188074
188211
  });
188075
188212
  var leadingParameterNameCommentRegexFactory = (name) => {
@@ -188870,7 +189007,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
188870
189007
  }
188871
189008
  }
188872
189009
  var ts_JsDoc_exports = {};
188873
- __export(ts_JsDoc_exports, {
189010
+ __export2(ts_JsDoc_exports, {
188874
189011
  getDocCommentTemplateAtPosition: () => getDocCommentTemplateAtPosition,
188875
189012
  getJSDocParameterNameCompletionDetails: () => getJSDocParameterNameCompletionDetails,
188876
189013
  getJSDocParameterNameCompletions: () => getJSDocParameterNameCompletions,
@@ -189307,7 +189444,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
189307
189444
  }
189308
189445
  }
189309
189446
  var ts_MapCode_exports = {};
189310
- __export(ts_MapCode_exports, {
189447
+ __export2(ts_MapCode_exports, {
189311
189448
  mapCode: () => mapCode
189312
189449
  });
189313
189450
  function mapCode(sourceFile, contents, focusLocations, host, formatContext, preferences) {
@@ -189511,7 +189648,7 @@ ${content}
189511
189648
  node.forEachChild(resetNodePositions);
189512
189649
  }
189513
189650
  var ts_OrganizeImports_exports = {};
189514
- __export(ts_OrganizeImports_exports, {
189651
+ __export2(ts_OrganizeImports_exports, {
189515
189652
  compareImportsOrRequireStatements: () => compareImportsOrRequireStatements,
189516
189653
  compareModuleSpecifiers: () => compareModuleSpecifiers2,
189517
189654
  getImportDeclarationInsertionIndex: () => getImportDeclarationInsertionIndex,
@@ -190171,7 +190308,7 @@ ${content}
190171
190308
  return compareModuleSpecifiersWorker(m1, m2, comparer);
190172
190309
  }
190173
190310
  var ts_OutliningElementsCollector_exports = {};
190174
- __export(ts_OutliningElementsCollector_exports, {
190311
+ __export2(ts_OutliningElementsCollector_exports, {
190175
190312
  collectElements: () => collectElements
190176
190313
  });
190177
190314
  function collectElements(sourceFile, cancellationToken) {
@@ -190590,7 +190727,7 @@ ${content}
190590
190727
  return findChildOfKind(body, 19, sourceFile);
190591
190728
  }
190592
190729
  var ts_Rename_exports = {};
190593
- __export(ts_Rename_exports, {
190730
+ __export2(ts_Rename_exports, {
190594
190731
  getRenameInfo: () => getRenameInfo,
190595
190732
  nodeIsEligibleForRename: () => nodeIsEligibleForRename
190596
190733
  });
@@ -190746,7 +190883,7 @@ ${content}
190746
190883
  }
190747
190884
  }
190748
190885
  var ts_SignatureHelp_exports = {};
190749
- __export(ts_SignatureHelp_exports, {
190886
+ __export2(ts_SignatureHelp_exports, {
190750
190887
  getArgumentInfoForCompletions: () => getArgumentInfoForCompletions,
190751
190888
  getSignatureHelpItems: () => getSignatureHelpItems
190752
190889
  });
@@ -191292,7 +191429,7 @@ ${content}
191292
191429
  return { name: typeParameter.symbol.name, documentation: typeParameter.symbol.getDocumentationComment(checker), displayParts, isOptional: false, isRest: false };
191293
191430
  }
191294
191431
  var ts_SmartSelectionRange_exports = {};
191295
- __export(ts_SmartSelectionRange_exports, {
191432
+ __export2(ts_SmartSelectionRange_exports, {
191296
191433
  getSmartSelectionRange: () => getSmartSelectionRange
191297
191434
  });
191298
191435
  function getSmartSelectionRange(pos, sourceFile) {
@@ -191523,7 +191660,7 @@ ${content}
191523
191660
  }
191524
191661
  }
191525
191662
  var ts_SymbolDisplay_exports = {};
191526
- __export(ts_SymbolDisplay_exports, {
191663
+ __export2(ts_SymbolDisplay_exports, {
191527
191664
  getSymbolDisplayPartsDocumentationAndSymbolKind: () => getSymbolDisplayPartsDocumentationAndSymbolKind,
191528
191665
  getSymbolKind: () => getSymbolKind,
191529
191666
  getSymbolModifiers: () => getSymbolModifiers
@@ -192491,7 +192628,7 @@ ${content}
192491
192628
  });
192492
192629
  }
192493
192630
  var ts_textChanges_exports = {};
192494
- __export(ts_textChanges_exports, {
192631
+ __export2(ts_textChanges_exports, {
192495
192632
  ChangeTracker: () => ChangeTracker,
192496
192633
  LeadingTriviaOption: () => LeadingTriviaOption,
192497
192634
  TrailingTriviaOption: () => TrailingTriviaOption,
@@ -193908,7 +194045,7 @@ ${options.prefix}` : "\n" : options.prefix
193908
194045
  });
193909
194046
  }
193910
194047
  var ts_formatting_exports = {};
193911
- __export(ts_formatting_exports, {
194048
+ __export2(ts_formatting_exports, {
193912
194049
  FormattingContext: () => FormattingContext,
193913
194050
  FormattingRequestKind: () => FormattingRequestKind,
193914
194051
  RuleAction: () => RuleAction,
@@ -197808,7 +197945,7 @@ ${options.prefix}` : "\n" : options.prefix
197808
197945
  }
197809
197946
  })(SmartIndenter || (SmartIndenter = {}));
197810
197947
  var ts_preparePasteEdits_exports = {};
197811
- __export(ts_preparePasteEdits_exports, {
197948
+ __export2(ts_preparePasteEdits_exports, {
197812
197949
  preparePasteEdits: () => preparePasteEdits
197813
197950
  });
197814
197951
  function preparePasteEdits(sourceFile, copiedFromRange, checker) {
@@ -197846,7 +197983,7 @@ ${options.prefix}` : "\n" : options.prefix
197846
197983
  return shouldProvidePasteEdits;
197847
197984
  }
197848
197985
  var ts_PasteEdits_exports = {};
197849
- __export(ts_PasteEdits_exports, {
197986
+ __export2(ts_PasteEdits_exports, {
197850
197987
  pasteEditsProvider: () => pasteEditsProvider
197851
197988
  });
197852
197989
  var fixId55 = "providePostPasteEdits";
@@ -197953,7 +198090,7 @@ ${options.prefix}` : "\n" : options.prefix
197953
198090
  };
197954
198091
  }
197955
198092
  var ts_exports2 = {};
197956
- __export(ts_exports2, {
198093
+ __export2(ts_exports2, {
197957
198094
  ANONYMOUS: () => ANONYMOUS,
197958
198095
  AccessFlags: () => AccessFlags,
197959
198096
  AssertionLevel: () => AssertionLevel,
@@ -200304,7 +200441,7 @@ ${options.prefix}` : "\n" : options.prefix
200304
200441
  };
200305
200442
  }
200306
200443
  var ts_server_exports3 = {};
200307
- __export(ts_server_exports3, {
200444
+ __export2(ts_server_exports3, {
200308
200445
  ActionInvalidate: () => ActionInvalidate,
200309
200446
  ActionPackageInstalled: () => ActionPackageInstalled,
200310
200447
  ActionSet: () => ActionSet,
@@ -200402,7 +200539,7 @@ ${options.prefix}` : "\n" : options.prefix
200402
200539
  updateProjectIfDirty: () => updateProjectIfDirty
200403
200540
  });
200404
200541
  var ts_server_typingsInstaller_exports = {};
200405
- __export(ts_server_typingsInstaller_exports, {
200542
+ __export2(ts_server_typingsInstaller_exports, {
200406
200543
  TypingsInstaller: () => TypingsInstaller,
200407
200544
  getNpmCommandForInstallation: () => getNpmCommandForInstallation,
200408
200545
  installNpmPackages: () => installNpmPackages,
@@ -200969,7 +201106,7 @@ ${options.prefix}` : "\n" : options.prefix
200969
201106
  return base === "tsconfig.json" || base === "jsconfig.json" ? base : void 0;
200970
201107
  }
200971
201108
  var ts_server_protocol_exports = {};
200972
- __export(ts_server_protocol_exports, {
201109
+ __export2(ts_server_protocol_exports, {
200973
201110
  ClassificationType: () => ClassificationType,
200974
201111
  CommandTypes: () => CommandTypes,
200975
201112
  CompletionTriggerKind: () => CompletionTriggerKind,
@@ -213043,7 +213180,7 @@ Additional information: BADCLIENT: Bad error code, ${badCode} not found in range
213043
213180
  _TypingsInstallerAdapter.requestDelayMillis = 100;
213044
213181
  var TypingsInstallerAdapter = _TypingsInstallerAdapter;
213045
213182
  var ts_server_exports4 = {};
213046
- __export(ts_server_exports4, {
213183
+ __export2(ts_server_exports4, {
213047
213184
  ActionInvalidate: () => ActionInvalidate,
213048
213185
  ActionPackageInstalled: () => ActionPackageInstalled,
213049
213186
  ActionSet: () => ActionSet,
@@ -214209,122 +214346,35 @@ var require_dist = __commonJS({
214209
214346
  }
214210
214347
  });
214211
214348
 
214212
- // src/api-client.ts
214213
- var import_node_http = require("node:http");
214214
- var import_node_https = require("node:https");
214215
- var import_node_fs = require("node:fs");
214216
- var import_node_path = require("node:path");
214217
- var import_node_os = require("node:os");
214218
- var CONFIG_PATH = (0, import_node_path.resolve)((0, import_node_os.homedir)(), ".driftless", "config.json");
214219
- function loadApiKey() {
214220
- const envKey = process.env["DRIFTLESS_API_KEY"];
214221
- if (envKey) return envKey;
214222
- try {
214223
- if ((0, import_node_fs.existsSync)(CONFIG_PATH)) {
214224
- const config = JSON.parse((0, import_node_fs.readFileSync)(CONFIG_PATH, "utf8"));
214225
- return config.api_key || null;
214226
- }
214227
- } catch {
214228
- }
214229
- return null;
214230
- }
214231
- var DEFAULT_URL = "http://localhost:3000/api/v1";
214232
- function getBaseUrl() {
214233
- const envUrl = process.env["DRIFTLESS_API_URL"];
214234
- if (envUrl) {
214235
- return envUrl.endsWith("/api/v1") ? envUrl : `${envUrl}/api/v1`;
214236
- }
214237
- try {
214238
- if ((0, import_node_fs.existsSync)(CONFIG_PATH)) {
214239
- const config = JSON.parse((0, import_node_fs.readFileSync)(CONFIG_PATH, "utf8"));
214240
- return config.api_url || DEFAULT_URL;
214241
- }
214242
- } catch {
214243
- }
214244
- return DEFAULT_URL;
214349
+ // src/analytics.ts
214350
+ var analytics_exports = {};
214351
+ __export(analytics_exports, {
214352
+ analyticsEvent: () => analyticsEvent
214353
+ });
214354
+ function analyticsEvent(event, distinctId, props = {}) {
214355
+ if (!KEY) return;
214356
+ fetch(`${HOST}/capture/`, {
214357
+ method: "POST",
214358
+ headers: { "Content-Type": "application/json" },
214359
+ body: JSON.stringify({
214360
+ api_key: KEY,
214361
+ event,
214362
+ distinct_id: `workspace:${distinctId}`,
214363
+ properties: { ...props, source: "cli", $lib: "driftless-cli" }
214364
+ })
214365
+ }).catch(() => void 0);
214245
214366
  }
214246
- function parseError(e) {
214247
- const msg = e.message;
214248
- const jsonMatch = msg.match(/\{[\s\S]*\}/);
214249
- if (jsonMatch) {
214250
- try {
214251
- const parsed = JSON.parse(jsonMatch[0]);
214252
- const parts = [];
214253
- if (parsed.message) parts.push(parsed.message);
214254
- if (parsed.request_id) parts.push(`request_id: ${parsed.request_id}`);
214255
- if (parsed.retryable !== void 0) parts.push(`retryable: ${parsed.retryable ? "yes" : "no"}`);
214256
- if (parsed.endpoint) parts.push(`endpoint: ${parsed.endpoint}`);
214257
- if (parts.length > 0) return parts.join(" | ");
214258
- } catch {
214259
- }
214260
- }
214261
- const statusMatch = msg.match(/HTTP (\d+):/);
214262
- if (statusMatch) {
214263
- const code = parseInt(statusMatch[1], 10);
214264
- if (code === 500) return "Internal server error \u2014 the API encountered an unexpected issue";
214265
- if (code === 401) return "Authentication failed \u2014 check your API key";
214266
- if (code === 403) return "Access denied \u2014 your API key lacks permission";
214267
- if (code === 404) return "Not found \u2014 the resource does not exist";
214268
- if (code === 429) return "Rate limited \u2014 too many requests, try again later";
214269
- return `Server error (HTTP ${code})`;
214367
+ var KEY, HOST;
214368
+ var init_analytics = __esm({
214369
+ "src/analytics.ts"() {
214370
+ "use strict";
214371
+ KEY = "";
214372
+ HOST = "https://us.i.posthog.com";
214270
214373
  }
214271
- return msg;
214272
- }
214273
- function request(method, path, body) {
214274
- return new Promise((resolve8, reject) => {
214275
- const baseUrl = getBaseUrl();
214276
- const fullUrl = `${baseUrl}${path}`;
214277
- const url = new URL(fullUrl);
214278
- const isHttps = url.protocol === "https:";
214279
- const fn = isHttps ? import_node_https.request : import_node_http.request;
214280
- const headers = {
214281
- "Content-Type": "application/json",
214282
- Accept: "application/json"
214283
- };
214284
- const apiKey = loadApiKey();
214285
- if (apiKey) {
214286
- headers["X-API-Key"] = apiKey;
214287
- }
214288
- const req = fn(
214289
- fullUrl,
214290
- { method, headers },
214291
- (res) => {
214292
- let data = "";
214293
- res.on("data", (chunk) => data += chunk.toString());
214294
- res.on("end", () => {
214295
- if (res.statusCode && res.statusCode >= 400) {
214296
- reject(new Error(`HTTP ${res.statusCode}: ${data}`));
214297
- return;
214298
- }
214299
- try {
214300
- resolve8(JSON.parse(data));
214301
- } catch {
214302
- resolve8(data);
214303
- }
214304
- });
214305
- }
214306
- );
214307
- req.on("error", (e) => reject(new Error(`Connection failed: ${e.message}`)));
214308
- if (body) req.write(JSON.stringify(body));
214309
- req.end();
214310
- });
214311
- }
214312
- var api = {
214313
- get: (path) => request("GET", path),
214314
- post: (path, body) => request("POST", path, body),
214315
- put: (path, body) => request("PUT", path, body),
214316
- patch: (path, body) => request("PATCH", path, body),
214317
- delete: (path) => request("DELETE", path)
214318
- };
214319
- function getApiUrl() {
214320
- return getBaseUrl();
214321
- }
214322
- function getApiKey() {
214323
- return loadApiKey();
214324
- }
214325
- function formatError(e) {
214326
- return parseError(e);
214327
- }
214374
+ });
214375
+
214376
+ // src/commands/init.ts
214377
+ init_api_client();
214328
214378
 
214329
214379
  // src/git.ts
214330
214380
  var import_node_child_process = require("node:child_process");
@@ -214401,6 +214451,7 @@ function getAuthorName() {
214401
214451
  var import_scanner = __toESM(require_dist());
214402
214452
  var import_node_fs4 = require("node:fs");
214403
214453
  var import_node_path4 = require("node:path");
214454
+ init_analytics();
214404
214455
 
214405
214456
  // src/commands/install-skill.ts
214406
214457
  var import_node_fs3 = require("node:fs");
@@ -214501,13 +214552,22 @@ async function installSkillCommand() {
214501
214552
  const icon = (s) => s === "created" ? "created \u2713" : s === "updated" ? "updated \u2713" : "already configured \u2713";
214502
214553
  console.log(` CLAUDE.md ${icon(result.claudeMd)}`);
214503
214554
  console.log(` AGENTS.md ${icon(result.agentsMd)}`);
214555
+ try {
214556
+ const { api: api2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
214557
+ const me = await api2.get("/me");
214558
+ if (me?.slug) {
214559
+ const { analyticsEvent: analyticsEvent2 } = await Promise.resolve().then(() => (init_analytics(), analytics_exports));
214560
+ analyticsEvent2("cli_install_skill", me.slug, { claude_md: result.claudeMd, agents_md: result.agentsMd });
214561
+ }
214562
+ } catch {
214563
+ }
214504
214564
  return result;
214505
214565
  }
214506
214566
 
214507
214567
  // src/commands/init.ts
214508
214568
  function getVersion() {
214509
214569
  try {
214510
- return "0.1.33";
214570
+ return "0.1.35";
214511
214571
  } catch {
214512
214572
  return "0.0.0";
214513
214573
  }
@@ -214806,6 +214866,15 @@ function step(label, value) {
214806
214866
  }
214807
214867
  async function initCommand(args) {
214808
214868
  const version = getVersion();
214869
+ let srcOverride;
214870
+ let suggest = false;
214871
+ for (let i = 0; i < args.length; i++) {
214872
+ if (args[i] === "--src" && i + 1 < args.length && !args[i + 1].startsWith("--")) {
214873
+ srcOverride = args[++i];
214874
+ } else if (args[i] === "--suggest") {
214875
+ suggest = true;
214876
+ }
214877
+ }
214809
214878
  console.log("D R I F T L E S S");
214810
214879
  console.log(`v${version}`);
214811
214880
  console.log("");
@@ -214841,10 +214910,12 @@ async function initCommand(args) {
214841
214910
  const workspaceSlug = workspace.slug;
214842
214911
  console.log(`Repository: ${remote.org}/${remote.repo}`);
214843
214912
  console.log(`Workspace: ${workspaceSlug} \u2713`);
214913
+ if (srcOverride) console.log(`Scan root: ${srcOverride}`);
214844
214914
  console.log("");
214845
214915
  const cwd = process.cwd();
214916
+ const scanRoot = srcOverride ? (0, import_node_path4.resolve)(cwd, srcOverride) : cwd;
214846
214917
  const scanStart = Date.now();
214847
- const scanResult = await (0, import_scanner.scanRepo)(cwd);
214918
+ const scanResult = await (0, import_scanner.scanRepo)(scanRoot);
214848
214919
  const scanMs = Date.now() - scanStart;
214849
214920
  const earlyPatterns = analyzeCodePatterns(scanResult.components);
214850
214921
  const summary = {
@@ -214916,46 +214987,53 @@ async function initCommand(args) {
214916
214987
  step("uploading components", "failed (continuing)");
214917
214988
  }
214918
214989
  }
214919
- const patterns = earlyPatterns;
214920
- const smartRules = generateSmartRules(repo.id, patterns);
214921
214990
  let rulesCreated = 0;
214922
- let rulesSkipped = 0;
214923
- for (const rule of smartRules) {
214924
- try {
214925
- const result = await api.post(`/workspaces/${workspaceSlug}/rules`, { ...rule, auto_suggested: true });
214926
- if (result?.skipped) {
214991
+ if (suggest) {
214992
+ const smartRules = generateSmartRules(repo.id, earlyPatterns);
214993
+ let rulesSkipped = 0;
214994
+ for (const rule of smartRules) {
214995
+ try {
214996
+ const result = await api.post(`/workspaces/${workspaceSlug}/rules`, { ...rule, auto_suggested: true });
214997
+ if (result?.skipped) rulesSkipped++;
214998
+ else rulesCreated++;
214999
+ } catch {
214927
215000
  rulesSkipped++;
214928
- } else {
214929
- rulesCreated++;
214930
215001
  }
214931
- } catch {
214932
- rulesSkipped++;
214933
215002
  }
215003
+ step("creating rules", `${rulesCreated} created \xB7 ${rulesSkipped} skipped \u2713`);
215004
+ } else {
215005
+ step("creating rules", "skipped (use --suggest to auto-generate)");
214934
215006
  }
214935
- step("creating rules", `${rulesCreated} created \xB7 ${rulesSkipped} skipped \u2713`);
214936
- const smartWatchers = generateSmartWatchers(components);
214937
215007
  let watchersCreated = 0;
214938
- let watchersSkipped = 0;
214939
- for (const watcher of smartWatchers) {
214940
- try {
214941
- await api.post(`/workspaces/${workspaceSlug}/watchers`, {
214942
- name: watcher.name,
214943
- what: watcher.what,
214944
- how: watcher.how,
214945
- pattern: watcher.pattern,
214946
- decisions: watcher.decisions,
214947
- gotchas: watcher.gotchas,
214948
- ownership: watcher.ownership,
214949
- where_repos: [repo.id],
214950
- created_by: "driftless-init",
214951
- suggested: true
214952
- });
214953
- watchersCreated++;
214954
- } catch {
214955
- watchersSkipped++;
215008
+ if (suggest) {
215009
+ const smartWatchers = generateSmartWatchers(components);
215010
+ let watchersSkipped = 0;
215011
+ for (const watcher of smartWatchers) {
215012
+ try {
215013
+ await api.post(`/workspaces/${workspaceSlug}/watchers`, {
215014
+ name: watcher.name,
215015
+ what: watcher.what,
215016
+ how: watcher.how,
215017
+ pattern: watcher.pattern,
215018
+ decisions: watcher.decisions,
215019
+ gotchas: watcher.gotchas,
215020
+ ownership: watcher.ownership,
215021
+ where_repos: [repo.id],
215022
+ created_by: "driftless-init",
215023
+ suggested: true,
215024
+ origin: "auto",
215025
+ status: "draft",
215026
+ kind: "domain-map"
215027
+ });
215028
+ watchersCreated++;
215029
+ } catch {
215030
+ watchersSkipped++;
215031
+ }
214956
215032
  }
215033
+ step("creating context", `${watchersCreated} topics \u2713`);
215034
+ } else {
215035
+ step("creating context", "skipped (use --suggest to auto-generate)");
214957
215036
  }
214958
- step("creating context", `${watchersCreated} watchers \u2713`);
214959
215037
  const existingDocs = detectExistingDocs(cwd);
214960
215038
  step("detecting docs", `${existingDocs.length} found (not auto-synced)`);
214961
215039
  let skillLine = "skipped";
@@ -214969,8 +215047,8 @@ async function initCommand(args) {
214969
215047
  step("installing skill", skillLine);
214970
215048
  console.log("");
214971
215049
  console.log("\u2713 repo context bootstrapped");
214972
- console.log(` \u251C\u2500 watchers ${watchersCreated}`);
214973
- console.log(` \u251C\u2500 rules ${rulesCreated}`);
215050
+ console.log(` \u251C\u2500 topics ${suggest ? watchersCreated : "(use --suggest to generate)"}`);
215051
+ console.log(` \u251C\u2500 rules ${suggest ? rulesCreated : "(use --suggest to generate)"}`);
214974
215052
  console.log(` \u251C\u2500 docs found ${existingDocs.length} (ask your agent to sync them)`);
214975
215053
  console.log(` \u251C\u2500 components ${components.length}`);
214976
215054
  console.log(` \u2514\u2500 relations ${relationCount}`);
@@ -214979,10 +215057,18 @@ async function initCommand(args) {
214979
215057
  console.log(" next \u2192 driftless context list");
214980
215058
  console.log("");
214981
215059
  console.log(DIVIDER);
215060
+ analyticsEvent("cli_init_run", workspaceSlug, {
215061
+ framework: summary.framework,
215062
+ endpoints: summary.endpoints ?? components.filter((c) => c.type === "controller").length,
215063
+ components: components.length,
215064
+ watchers_created: watchersCreated
215065
+ });
214982
215066
  process.exit(0);
214983
215067
  }
214984
215068
 
214985
215069
  // src/commands/scan.ts
215070
+ init_api_client();
215071
+ init_analytics();
214986
215072
  function emitJSON(data) {
214987
215073
  console.log(JSON.stringify(data, null, 2));
214988
215074
  }
@@ -215058,6 +215144,7 @@ async function scanCommand(args) {
215058
215144
  });
215059
215145
  const rulesEvaluated = result.rules_evaluated || 0;
215060
215146
  if (result.status === "clean") {
215147
+ analyticsEvent("cli_scan_run", workspace.slug, { violations_found: false, count: 0 });
215061
215148
  if (isJSON) {
215062
215149
  emitJSON({ status: "clean", files: changedFiles, rules_evaluated: rulesEvaluated, violations: [] });
215063
215150
  } else {
@@ -215066,6 +215153,7 @@ async function scanCommand(args) {
215066
215153
  process.exit(0);
215067
215154
  }
215068
215155
  if (!result.violations || result.violations.length === 0) {
215156
+ analyticsEvent("cli_scan_run", workspace.slug, { violations_found: false, count: 0 });
215069
215157
  if (isJSON) {
215070
215158
  emitJSON({ status: "clean", files: changedFiles, rules_evaluated: rulesEvaluated, violations: [] });
215071
215159
  } else {
@@ -215073,6 +215161,7 @@ async function scanCommand(args) {
215073
215161
  }
215074
215162
  process.exit(0);
215075
215163
  }
215164
+ analyticsEvent("cli_scan_run", workspace.slug, { violations_found: true, count: result.violations.length });
215076
215165
  if (isJSON) {
215077
215166
  emitJSON({ status: "violated", files: changedFiles, rules_evaluated: rulesEvaluated, violations: result.violations });
215078
215167
  } else {
@@ -215093,8 +215182,10 @@ ${result.violations.length} violation(s) found (${rulesEvaluated} rule(s) evalua
215093
215182
  }
215094
215183
 
215095
215184
  // src/commands/context.ts
215185
+ init_api_client();
215096
215186
  var import_node_fs5 = require("node:fs");
215097
215187
  var import_node_path5 = require("node:path");
215188
+ init_analytics();
215098
215189
  function parseArgs(args) {
215099
215190
  const flags = {};
215100
215191
  const positional = [];
@@ -215139,10 +215230,12 @@ function renderSummaryHuman(items) {
215139
215230
  }
215140
215231
  const topicWidth = Math.max(...items.map((i) => i.topic.length), 12) + 2;
215141
215232
  const badgeWidth = Math.max(...items.map((i) => formatBadges(i.badges).length), 8) + 2;
215233
+ const statusWidth = Math.max(...items.map((i) => (i.classification?.status || "").length), 8) + 2;
215142
215234
  for (const item of items) {
215143
215235
  const topic = pad(item.topic, topicWidth);
215144
215236
  const badges = pad(formatBadges(item.badges), badgeWidth);
215145
- console.log(`${topic}${badges}${item.summary}`);
215237
+ const status = pad(item.classification?.status || "", statusWidth);
215238
+ console.log(`${topic}${status}${badges}${item.summary}`);
215146
215239
  }
215147
215240
  console.log(`
215148
215241
  ${items.length} topic${items.length === 1 ? "" : "s"}.`);
@@ -215151,11 +215244,19 @@ function renderContextHuman(ctx) {
215151
215244
  console.log(`\u258C ${ctx.topic}`);
215152
215245
  console.log(` ${ctx.summary}`);
215153
215246
  if (ctx.version !== void 0) console.log(` version: ${ctx.version}`);
215247
+ if (ctx.classification) {
215248
+ const { origin, status, kind } = ctx.classification;
215249
+ console.log(` origin: ${origin} status: ${status} kind: ${kind}`);
215250
+ }
215154
215251
  if (ctx.stale.is_stale) {
215155
215252
  console.log(`
215156
215253
  \u26A0 STALE: ${ctx.stale.reason || "Context may be outdated"}`);
215157
215254
  console.log(` \u2192 driftless context update ${ctx.topic} --what "..." --how "..."`);
215158
215255
  }
215256
+ if (ctx.metadata.created_by === "driftless-init") {
215257
+ console.log(`
215258
+ \u24D8 auto-suggested by init \u2014 confirm with \`driftless context update ${ctx.topic} --what "..."\``);
215259
+ }
215159
215260
  console.log("");
215160
215261
  if (ctx.description.what) console.log(` what: ${ctx.description.what}`);
215161
215262
  if (ctx.description.how) console.log(` how: ${ctx.description.how}`);
@@ -215284,9 +215385,23 @@ async function contextCommand(args) {
215284
215385
  if (flags["docs"]) query.push("docs=true");
215285
215386
  if (flags["auto"]) query.push("auto=true");
215286
215387
  if (flags["manual"]) query.push("manual=true");
215287
- if (flags["repo"]) query.push(`repo=${encodeURIComponent(flags["repo"])}`);
215288
215388
  if (flags["suggested"]) query.push("suggested=true");
215289
215389
  else query.push("suggested=false");
215390
+ if (flags["status"]) query.push(`status=${encodeURIComponent(flags["status"])}`);
215391
+ if (flags["kind"]) query.push(`kind=${encodeURIComponent(flags["kind"])}`);
215392
+ if (flags["repo"]) {
215393
+ query.push(`repo=${encodeURIComponent(flags["repo"])}`);
215394
+ } else if (flags["auto"]) {
215395
+ const currentRemote = getGitRemote();
215396
+ if (currentRemote) {
215397
+ try {
215398
+ const repos = await api.get(`/workspaces/${workspaceSlug}/repos`);
215399
+ const match = repos.find((r) => r.github_org === currentRemote.org && r.github_repo === currentRemote.repo);
215400
+ if (match) query.push(`repo=${encodeURIComponent(match.id)}`);
215401
+ } catch {
215402
+ }
215403
+ }
215404
+ }
215290
215405
  const qs = query.length > 0 ? `?${query.join("&")}` : "";
215291
215406
  try {
215292
215407
  const summaries = await api.get(`/workspaces/${workspaceSlug}/watchers${qs}`);
@@ -215365,6 +215480,7 @@ async function contextCommand(args) {
215365
215480
  }
215366
215481
  try {
215367
215482
  const ctx = await api.get(`/workspaces/${workspaceSlug}/watchers/${slug}`);
215483
+ analyticsEvent("cli_context_get", workspaceSlug, { topic: slug });
215368
215484
  if (isJSON) {
215369
215485
  const sanitized = JSON.parse(JSON.stringify(ctx, (_key, value) => {
215370
215486
  if (typeof value === "string" && value.length > 500) return value.slice(0, 500) + "\u2026";
@@ -215421,6 +215537,9 @@ async function contextCommand(args) {
215421
215537
  }
215422
215538
  const pattern = flags["pattern"];
215423
215539
  if (pattern && !isJSON) {
215540
+ if (pattern.includes(",")) {
215541
+ console.error(`Warning: pattern "${pattern}" contains a comma. Only one glob is accepted per topic. Create separate topics or remove the comma.`);
215542
+ }
215424
215543
  const localCount = countLocalFilesMatching(pattern);
215425
215544
  if (localCount === 0) {
215426
215545
  console.error(`Warning: pattern "${pattern}" matches 0 files locally. Topic created anyway.`);
@@ -215436,8 +215555,11 @@ async function contextCommand(args) {
215436
215555
  decisions: flags["decisions"],
215437
215556
  gotchas: flags["gotchas"],
215438
215557
  ownership: flags["ownership"],
215439
- file_content: fileContent
215558
+ file_content: fileContent,
215559
+ status: flags["status"],
215560
+ kind: flags["kind"]
215440
215561
  });
215562
+ analyticsEvent("context_created", workspaceSlug, { topic: name, has_pattern: !!pattern, has_what: !!flags["what"] });
215441
215563
  if (isJSON) {
215442
215564
  emitJSON2(result);
215443
215565
  } else {
@@ -215466,12 +215588,21 @@ async function contextCommand(args) {
215466
215588
  if (flags["decisions"]) updates.decisions = flags["decisions"];
215467
215589
  if (flags["gotchas"]) updates.gotchas = flags["gotchas"];
215468
215590
  if (flags["ownership"]) updates.ownership = flags["ownership"];
215469
- const gotchaFlag = flags["gotcha"] || flags["gotchas_append"];
215470
- if (gotchaFlag) updates._append_gotchas = gotchaFlag;
215471
- const invariantFlag = flags["invariant"];
215472
- if (invariantFlag) updates._append_invariants = invariantFlag;
215473
- const checkFlag = flags["check"];
215474
- if (checkFlag) updates._append_required_checks = checkFlag;
215591
+ if (flags["status"]) updates.status = flags["status"];
215592
+ const gotchaValues = [];
215593
+ const invariantValues = [];
215594
+ const checkValues = [];
215595
+ for (let i = 0; i < args.length - 1; i++) {
215596
+ const a = args[i];
215597
+ const b = args[i + 1];
215598
+ if (!b || b.startsWith("--")) continue;
215599
+ if (a === "--gotcha" || a === "--gotchas_append") gotchaValues.push(b);
215600
+ if (a === "--invariant") invariantValues.push(b);
215601
+ if (a === "--check") checkValues.push(b);
215602
+ }
215603
+ if (gotchaValues.length > 0) updates._append_gotchas = gotchaValues.join("\n");
215604
+ if (invariantValues.length > 0) updates._append_invariants = invariantValues.join("\n");
215605
+ if (checkValues.length > 0) updates._append_required_checks = checkValues.join("\n");
215475
215606
  const enforceFlag = flags["enforce"];
215476
215607
  if (enforceFlag && typeof enforceFlag === "string") {
215477
215608
  updates._enforce_rule = enforceFlag;
@@ -215479,16 +215610,18 @@ async function contextCommand(args) {
215479
215610
  updates._enforce_rule = true;
215480
215611
  }
215481
215612
  const eventParts = [];
215482
- if (gotchaFlag) eventParts.push(`gotcha appended`);
215483
- if (invariantFlag) eventParts.push(`invariant appended`);
215484
- if (checkFlag) eventParts.push(`check appended`);
215613
+ if (gotchaValues.length > 0) eventParts.push(`gotcha appended`);
215614
+ if (invariantValues.length > 0) eventParts.push(`invariant appended`);
215615
+ if (checkValues.length > 0) eventParts.push(`check appended`);
215485
215616
  if (enforceFlag) eventParts.push(`enforce requested`);
215486
215617
  if (eventParts.length > 0) {
215487
215618
  updates._event_detail = `CONTEXT_UPDATED: ${eventParts.join(", ")}`;
215488
215619
  }
215489
215620
  if (Object.keys(updates).length === 0) {
215490
- console.error("No fields to update. Use --what, --how, --pattern, --decisions, --gotchas, --ownership");
215491
- console.error('PR 3: --gotcha, --invariant, --check, --enforce "<rule-description>"');
215621
+ console.error("No fields to update.");
215622
+ console.error("Scalar: --what, --how, --pattern, --decisions, --gotchas, --ownership");
215623
+ console.error("Append: --gotcha (repeatable), --invariant (repeatable), --check (repeatable)");
215624
+ console.error('Enforce: --enforce "<rule-description>"');
215492
215625
  process.exit(1);
215493
215626
  }
215494
215627
  const currentRemote = getGitRemote();
@@ -215520,6 +215653,7 @@ async function contextCommand(args) {
215520
215653
  `/workspaces/${workspaceSlug}/watchers/${slug}`,
215521
215654
  updates
215522
215655
  );
215656
+ analyticsEvent("cli_context_update", workspaceSlug, { topic: slug });
215523
215657
  if (isJSON) {
215524
215658
  emitJSON2(result);
215525
215659
  } else {
@@ -215596,7 +215730,12 @@ async function contextCommand(args) {
215596
215730
  }
215597
215731
  const updates = { last_updated: /* @__PURE__ */ new Date() };
215598
215732
  if (fileContent) updates.file_content = fileContent;
215599
- if (docFlag) updates.anchored_doc_path = docFlag;
215733
+ if (docFlag) {
215734
+ updates.anchored_doc_path = docFlag;
215735
+ updates.origin = "doc";
215736
+ updates.status = "draft";
215737
+ updates.kind = "docs-pending";
215738
+ }
215600
215739
  if (noteFlag) updates.decisions = noteFlag;
215601
215740
  if (filesFlag) updates.where_files = filesFlag.split(",").map((f) => f.trim()).filter(Boolean);
215602
215741
  if (patternFlag) updates.pattern = patternFlag;
@@ -215875,6 +216014,7 @@ Run 'driftless help context' for full reference.`);
215875
216014
  }
215876
216015
 
215877
216016
  // src/commands/sync.ts
216017
+ init_api_client();
215878
216018
  function parseArgs2(args) {
215879
216019
  const flags = {};
215880
216020
  for (let i = 0; i < args.length; i++) {
@@ -215927,18 +216067,18 @@ async function syncCommand(args) {
215927
216067
  }
215928
216068
  if (!repoId) {
215929
216069
  if (!isJSON) {
215930
- console.log(`Repo '${remote.org}/${remote.repo}' not found in workspace.`);
215931
- console.log("Run driftless init to register this repo first.");
216070
+ console.log(`\u26A0 Repo '${remote.org}/${remote.repo}' not found in workspace '${workspaceSlug}'.`);
216071
+ console.log(" Run `driftless init` to register this repo, or `driftless doctor` to diagnose.");
215932
216072
  } else {
215933
- emitJSON3({ error: "repo_not_found", repo: `${remote.org}/${remote.repo}` });
216073
+ emitJSON3({ error: "repo_not_found", repo: `${remote.org}/${remote.repo}`, workspace: workspaceSlug });
215934
216074
  }
215935
- process.exit(0);
216075
+ process.exit(1);
215936
216076
  }
215937
216077
  const [eventsRes, staleTopics, violations, suggestedTopics] = await Promise.allSettled([
215938
216078
  api.get(`/workspaces/${workspaceSlug}/watchers/events?repo_id=${repoId}&limit=20`),
215939
216079
  api.get(`/workspaces/${workspaceSlug}/watchers?stale=true&repo=${repoId}`),
215940
216080
  api.get(`/workspaces/${workspaceSlug}/violations?repo_id=${repoId}&status=open&limit=20`),
215941
- api.get(`/workspaces/${workspaceSlug}/watchers?suggested=true`)
216081
+ api.get(`/workspaces/${workspaceSlug}/watchers?suggested=true&repo=${repoId}`)
215942
216082
  ]);
215943
216083
  const events = eventsRes.status === "fulfilled" ? eventsRes.value.events ?? [] : [];
215944
216084
  const stale = staleTopics.status === "fulfilled" ? staleTopics.value : [];
@@ -216079,6 +216219,7 @@ function saveConfig(apiKey, apiUrl) {
216079
216219
  }
216080
216220
 
216081
216221
  // src/commands/doctor.ts
216222
+ init_api_client();
216082
216223
  var import_node_fs7 = require("node:fs");
216083
216224
  var import_node_path7 = require("node:path");
216084
216225
  async function doctorCommand() {
@@ -216186,13 +216327,18 @@ async function doctorCommand() {
216186
216327
  if (ghApp) {
216187
216328
  checks.push({ name: "GitHub App", status: "ok", detail: "Installed and active" });
216188
216329
  } else {
216189
- checks.push({ name: "GitHub App", status: "warn", detail: "Not installed. Install via dashboard Settings \u2192 GitHub" });
216330
+ checks.push({ name: "GitHub App", status: "warn", detail: "Not installed \u2014 driftless.icu/ecosystem \u2192 Settings \u2192 Integrations (if just installed, wait ~60s)" });
216331
+ }
216332
+ } catch (err) {
216333
+ const isNotFound = err?.status === 404 || String(err?.message ?? "").includes("404");
216334
+ if (isNotFound) {
216335
+ checks.push({ name: "GitHub App", status: "warn", detail: "Not installed \u2014 driftless.icu/ecosystem \u2192 Settings \u2192 Integrations" });
216336
+ } else {
216337
+ checks.push({ name: "GitHub App", status: "warn", detail: "Could not verify \u2014 check your connection or API key" });
216190
216338
  }
216191
- } catch {
216192
- checks.push({ name: "GitHub App", status: "warn", detail: "Could not verify" });
216193
216339
  }
216194
216340
  } else {
216195
- checks.push({ name: "GitHub App", status: "warn", detail: "Could not verify" });
216341
+ checks.push({ name: "GitHub App", status: "warn", detail: "Could not verify (workspace unknown)" });
216196
216342
  }
216197
216343
  } else {
216198
216344
  checks.push({ name: "GitHub App", status: "warn", detail: "Skipped (not a git repo)" });
@@ -216224,7 +216370,7 @@ function pad2(s, n) {
216224
216370
  }
216225
216371
 
216226
216372
  // src/index.ts
216227
- var VERSION = "0.1.33";
216373
+ var VERSION = "0.1.35";
216228
216374
  var HELP_TEXT = `Driftless CLI v${VERSION} \u2014 Living repo context for humans and coding agents
216229
216375
 
216230
216376
  Install: npm install -g @driftless-sh/cli
@@ -216241,7 +216387,7 @@ Agent loop:
216241
216387
 
216242
216388
  Setup:
216243
216389
  driftless login --key <api-key> Authenticate
216244
- driftless init Scan repo, bootstrap context, suggest rules
216390
+ driftless init [--src <path>] Scan repo, bootstrap context (add --suggest for auto topics+rules)
216245
216391
  driftless doctor Check environment health
216246
216392
 
216247
216393
  Commands:
@@ -216292,8 +216438,8 @@ Examples:
216292
216438
  driftless sync --json # machine-readable output
216293
216439
 
216294
216440
  driftless context add "b2b-guard" \\
216295
- --what "Guard que protege endpoints B2B" \\
216296
- --how "Verifica org_id en el token" \\
216441
+ --what "Guard protecting B2B endpoints" \\
216442
+ --how "Verifies org_id from the auth token" \\
216297
216443
  --pattern "src/shared/guards/**"
216298
216444
 
216299
216445
  driftless context get sdk
@@ -216315,22 +216461,30 @@ Options:
216315
216461
  Example:
216316
216462
  driftless login --key drift_xxx
216317
216463
  `,
216318
- init: `driftless init
216464
+ init: `driftless init [--src <path>] [--suggest]
216319
216465
 
216320
216466
  Smart initialization \u2014 zero friction:
216321
216467
  1. Detects framework, system type, auth patterns (Pass 1)
216322
216468
  2. AST scan: extracts endpoints, guards, services, modules, relations (Pass 2)
216323
216469
  3. Analyzes code patterns: guard enforcement, multi-tenant, large files, legacy
216324
216470
  4. Uploads baseline + components + relations to Cloud
216325
- 5. Creates specific rules from detected patterns (not generic ones)
216326
- 6. Creates context topics for each detected module with smart gotchas
216327
- 7. Detects existing docs (not auto-synced \u2014 ask your agent to sync them)
216471
+ 5. Detects existing docs (not auto-synced \u2014 ask your agent to sync them)
216472
+ 6. Installs AGENTS.md skill
216473
+
216474
+ With --suggest (optional):
216475
+ Also auto-generates rules and context topics from detected patterns.
216476
+
216477
+ Options:
216478
+ --src <path> Scan root relative to cwd (monorepo support).
216479
+ Git root stays at cwd; scanner starts from <path>.
216480
+ --suggest Auto-generate rules and context topics. Off by default.
216328
216481
 
216329
216482
  Must be run from a git repository root.
216330
216483
 
216331
- Example:
216332
- cd my-nestjs-repo
216484
+ Examples:
216333
216485
  driftless init
216486
+ driftless init --src apps/api/src
216487
+ driftless init --src apps/api/src --suggest
216334
216488
  `,
216335
216489
  scan: `driftless scan [--diff]
216336
216490
 
@@ -216427,25 +216581,53 @@ async function main() {
216427
216581
  const command = args[0];
216428
216582
  switch (command) {
216429
216583
  case "init":
216430
- await initCommand(args.slice(1));
216584
+ if (args[1] === "--help") {
216585
+ showCommandHelp("init");
216586
+ } else {
216587
+ await initCommand(args.slice(1));
216588
+ }
216431
216589
  break;
216432
216590
  case "scan":
216433
- await scanCommand(args.slice(1));
216591
+ if (args[1] === "--help") {
216592
+ showCommandHelp("scan");
216593
+ } else {
216594
+ await scanCommand(args.slice(1));
216595
+ }
216434
216596
  break;
216435
216597
  case "context":
216436
- await contextCommand(args.slice(1));
216598
+ if (args[1] === "--help") {
216599
+ showCommandHelp("context");
216600
+ } else {
216601
+ await contextCommand(args.slice(1));
216602
+ }
216437
216603
  break;
216438
216604
  case "sync":
216439
- await syncCommand(args.slice(1));
216605
+ if (args[1] === "--help") {
216606
+ showCommandHelp("sync");
216607
+ } else {
216608
+ await syncCommand(args.slice(1));
216609
+ }
216440
216610
  break;
216441
216611
  case "install-skill":
216442
- await installSkillCommand();
216612
+ if (args[1] === "--help") {
216613
+ showCommandHelp("install-skill");
216614
+ } else {
216615
+ await installSkillCommand();
216616
+ }
216443
216617
  break;
216444
216618
  case "login":
216445
- loginCommand(args.slice(1));
216619
+ if (args[1] === "--help") {
216620
+ showCommandHelp("login");
216621
+ } else {
216622
+ loginCommand(args.slice(1));
216623
+ }
216446
216624
  break;
216447
216625
  case "doctor":
216448
- await doctorCommand();
216626
+ if (args[1] === "--help") {
216627
+ showCommandHelp("doctor");
216628
+ } else {
216629
+ await doctorCommand();
216630
+ }
216449
216631
  break;
216450
216632
  case "help":
216451
216633
  if (args[1]) {