@hasna/instructions 0.4.19 → 0.4.21
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/README.md +12 -4
- package/dist/cli/add-reference-update.test.d.ts +2 -0
- package/dist/cli/add-reference-update.test.d.ts.map +1 -0
- package/dist/cli/doctor-reference-duplicates.test.d.ts +2 -0
- package/dist/cli/doctor-reference-duplicates.test.d.ts.map +1 -0
- package/dist/cli/index.js +366 -103
- package/dist/cli/profile-reads.test.d.ts +2 -0
- package/dist/cli/profile-reads.test.d.ts.map +1 -0
- package/dist/cli/profile-update.test.d.ts +2 -0
- package/dist/cli/profile-update.test.d.ts.map +1 -0
- package/dist/data/config-store.d.ts +10 -1
- package/dist/data/config-store.d.ts.map +1 -1
- package/dist/db/profiles.d.ts +4 -1
- package/dist/db/profiles.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +226 -30
- package/dist/lib/bounded-read.d.ts +7 -0
- package/dist/lib/bounded-read.d.ts.map +1 -0
- package/dist/lib/config-target-identity.d.ts +76 -0
- package/dist/lib/config-target-identity.d.ts.map +1 -1
- package/dist/lib/project-dashboard-standard.d.ts +1 -1
- package/dist/lib/project-dashboard-standard.d.ts.map +1 -1
- package/dist/mcp/index.js +314 -127
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/server/index.js +246 -36
- package/dist/server/openapi.d.ts +246 -20
- package/dist/server/openapi.d.ts.map +1 -1
- package/dist/server/profile-contract.test.d.ts +2 -0
- package/dist/server/profile-contract.test.d.ts.map +1 -0
- package/dist/server/v1.d.ts.map +1 -1
- package/dist/storage/cloud-store.d.ts +8 -1
- package/dist/storage/cloud-store.d.ts.map +1 -1
- package/dist/types/index.d.ts +24 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile-reads.test.d.ts","sourceRoot":"","sources":["../../src/cli/profile-reads.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile-update.test.d.ts","sourceRoot":"","sources":["../../src/cli/profile-update.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Database } from "bun:sqlite";
|
|
2
2
|
import { type FeedbackInput } from "../db/database.js";
|
|
3
|
-
import type { Config, ConfigFilter, ConfigSnapshot, CreateConfigInput, CreateProfileInput, Machine, MachineContext, Profile, UpdateConfigInput, UpdateProfileInput } from "../types/index.js";
|
|
3
|
+
import type { Config, ConfigFilter, ConfigSnapshot, CreateConfigInput, CreateProfileInput, Machine, MachineContext, Profile, BoundedReadOptions, BoundedReadPage, ProfileResolutionRead, UpdateConfigInput, UpdateProfileInput } from "../types/index.js";
|
|
4
4
|
export interface CloudConfig {
|
|
5
5
|
apiUrl: string;
|
|
6
6
|
apiKey: string;
|
|
@@ -52,14 +52,17 @@ export interface ConfigStore {
|
|
|
52
52
|
createSnapshot(configId: string, content: string, version: number): Promise<ConfigSnapshot>;
|
|
53
53
|
pruneSnapshots(configId: string, keep?: number): Promise<number>;
|
|
54
54
|
listProfiles(): Promise<Profile[]>;
|
|
55
|
+
listProfilesPage(options?: BoundedReadOptions): Promise<BoundedReadPage<Profile>>;
|
|
55
56
|
getProfile(idOrSlug: string): Promise<Profile>;
|
|
56
57
|
getProfileConfigs(idOrSlug: string): Promise<Config[]>;
|
|
58
|
+
getProfileConfigsPage(idOrSlug: string, options?: BoundedReadOptions): Promise<BoundedReadPage<Config>>;
|
|
57
59
|
createProfile(input: CreateProfileInput): Promise<Profile>;
|
|
58
60
|
updateProfile(idOrSlug: string, input: UpdateProfileInput): Promise<Profile>;
|
|
59
61
|
deleteProfile(idOrSlug: string): Promise<void>;
|
|
60
62
|
addConfigToProfile(profileIdOrSlug: string, configId: string): Promise<void>;
|
|
61
63
|
removeConfigFromProfile(profileIdOrSlug: string, configId: string): Promise<void>;
|
|
62
64
|
resolveProfileForMachine(machine?: MachineContext): Promise<Profile | null>;
|
|
65
|
+
resolveProfileForMachineRead(machine?: MachineContext, options?: BoundedReadOptions): Promise<ProfileResolutionRead>;
|
|
63
66
|
registerMachine(hostname?: string, os?: string, arch?: string): Promise<Machine>;
|
|
64
67
|
updateMachineApplied(hostname?: string): Promise<void>;
|
|
65
68
|
listMachines(): Promise<Machine[]>;
|
|
@@ -93,14 +96,17 @@ export declare class LocalConfigStore implements ConfigStore {
|
|
|
93
96
|
createSnapshot(configId: string, content: string, version: number): Promise<ConfigSnapshot>;
|
|
94
97
|
pruneSnapshots(configId: string, keep?: number): Promise<number>;
|
|
95
98
|
listProfiles(): Promise<Profile[]>;
|
|
99
|
+
listProfilesPage(options?: BoundedReadOptions): Promise<BoundedReadPage<Profile>>;
|
|
96
100
|
getProfile(idOrSlug: string): Promise<Profile>;
|
|
97
101
|
getProfileConfigs(idOrSlug: string): Promise<Config[]>;
|
|
102
|
+
getProfileConfigsPage(idOrSlug: string, options?: BoundedReadOptions): Promise<BoundedReadPage<Config>>;
|
|
98
103
|
createProfile(input: CreateProfileInput): Promise<Profile>;
|
|
99
104
|
updateProfile(idOrSlug: string, input: UpdateProfileInput): Promise<Profile>;
|
|
100
105
|
deleteProfile(idOrSlug: string): Promise<void>;
|
|
101
106
|
addConfigToProfile(profileIdOrSlug: string, configId: string): Promise<void>;
|
|
102
107
|
removeConfigFromProfile(profileIdOrSlug: string, configId: string): Promise<void>;
|
|
103
108
|
resolveProfileForMachine(machine?: MachineContext): Promise<Profile | null>;
|
|
109
|
+
resolveProfileForMachineRead(machine?: MachineContext, options?: BoundedReadOptions): Promise<ProfileResolutionRead>;
|
|
104
110
|
registerMachine(hostname?: string, os?: string, arch?: string): Promise<Machine>;
|
|
105
111
|
updateMachineApplied(hostname?: string): Promise<void>;
|
|
106
112
|
listMachines(): Promise<Machine[]>;
|
|
@@ -128,14 +134,17 @@ export declare class CloudConfigStore implements ConfigStore {
|
|
|
128
134
|
createSnapshot(configId: string, content: string, version: number): Promise<ConfigSnapshot>;
|
|
129
135
|
pruneSnapshots(configId: string, keep?: number): Promise<number>;
|
|
130
136
|
listProfiles(): Promise<Profile[]>;
|
|
137
|
+
listProfilesPage(options?: BoundedReadOptions): Promise<BoundedReadPage<Profile>>;
|
|
131
138
|
getProfile(idOrSlug: string): Promise<Profile>;
|
|
132
139
|
getProfileConfigs(idOrSlug: string): Promise<Config[]>;
|
|
140
|
+
getProfileConfigsPage(idOrSlug: string, options?: BoundedReadOptions): Promise<BoundedReadPage<Config>>;
|
|
133
141
|
createProfile(input: CreateProfileInput): Promise<Profile>;
|
|
134
142
|
updateProfile(idOrSlug: string, input: UpdateProfileInput): Promise<Profile>;
|
|
135
143
|
deleteProfile(idOrSlug: string): Promise<void>;
|
|
136
144
|
addConfigToProfile(profileIdOrSlug: string, configId: string): Promise<void>;
|
|
137
145
|
removeConfigFromProfile(profileIdOrSlug: string, configId: string): Promise<void>;
|
|
138
146
|
resolveProfileForMachine(machine?: MachineContext): Promise<Profile | null>;
|
|
147
|
+
resolveProfileForMachineRead(machine?: MachineContext, options?: BoundedReadOptions): Promise<ProfileResolutionRead>;
|
|
139
148
|
registerMachine(hostname?: string, os?: string, arch?: string): Promise<Machine>;
|
|
140
149
|
updateMachineApplied(hostname?: string): Promise<void>;
|
|
141
150
|
listMachines(): Promise<Machine[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../../src/data/config-store.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAiC3C,OAAO,EAAkF,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvI,OAAO,KAAK,EACV,MAAM,EACN,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,OAAO,EACP,cAAc,EACd,OAAO,EACP,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../../src/data/config-store.ts"],"names":[],"mappings":"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"}
|
package/dist/db/profiles.d.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import type { Database } from "bun:sqlite";
|
|
2
|
-
import type { Config, CreateProfileInput, Profile, UpdateProfileInput, MachineContext } from "../types/index.js";
|
|
2
|
+
import type { Config, CreateProfileInput, Profile, UpdateProfileInput, MachineContext, BoundedReadOptions, BoundedReadPage, ProfileResolutionRead } from "../types/index.js";
|
|
3
3
|
export declare function createProfile(input: CreateProfileInput, db?: Database): Profile;
|
|
4
4
|
export declare function getProfile(idOrSlug: string, db?: Database): Profile;
|
|
5
5
|
export declare function listProfiles(db?: Database): Profile[];
|
|
6
|
+
export declare function listProfilesPage(options?: BoundedReadOptions, db?: Database): BoundedReadPage<Profile>;
|
|
6
7
|
export declare function updateProfile(idOrSlug: string, input: UpdateProfileInput, db?: Database): Profile;
|
|
7
8
|
export declare function deleteProfile(idOrSlug: string, db?: Database): void;
|
|
8
9
|
export declare function addConfigToProfile(profileIdOrSlug: string, configId: string, db?: Database): void;
|
|
9
10
|
export declare function removeConfigFromProfile(profileIdOrSlug: string, configId: string, db?: Database): void;
|
|
10
11
|
export declare function getProfileConfigs(profileIdOrSlug: string, db?: Database): Config[];
|
|
12
|
+
export declare function getProfileConfigsPage(profileIdOrSlug: string, options?: BoundedReadOptions, db?: Database): BoundedReadPage<Config>;
|
|
11
13
|
export declare function profileHasSelectors(profile: Pick<Profile, "selectors">): boolean;
|
|
12
14
|
export declare function profileMatchesMachine(profile: Pick<Profile, "selectors">, machine: Pick<MachineContext, "hostname" | "os" | "arch" | "os_family">): boolean;
|
|
13
15
|
export declare function resolveProfileForMachine(machine?: MachineContext, db?: Database): Profile | null;
|
|
16
|
+
export declare function resolveProfileForMachineRead(machine?: MachineContext, options?: BoundedReadOptions, db?: Database): ProfileResolutionRead;
|
|
14
17
|
//# sourceMappingURL=profiles.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profiles.d.ts","sourceRoot":"","sources":["../../src/db/profiles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EACV,MAAM,EACN,kBAAkB,EAClB,OAAO,EAIP,kBAAkB,EAClB,cAAc,EACf,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"profiles.d.ts","sourceRoot":"","sources":["../../src/db/profiles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EACV,MAAM,EACN,kBAAkB,EAClB,OAAO,EAIP,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACtB,MAAM,mBAAmB,CAAC;AA4B3B,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAmB/E;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CASnE;AAED,wBAAgB,YAAY,CAAC,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,EAAE,CAMrD;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE,kBAAuB,EAChC,EAAE,CAAC,EAAE,QAAQ,GACZ,eAAe,CAAC,OAAO,CAAC,CAS1B;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,kBAAkB,EACzB,EAAE,CAAC,EAAE,QAAQ,GACZ,OAAO,CA0BT;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,CAInE;AAED,wBAAgB,kBAAkB,CAChC,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,EAAE,CAAC,EAAE,QAAQ,GACZ,IAAI,CAaN;AAED,wBAAgB,uBAAuB,CACrC,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,EAAE,CAAC,EAAE,QAAQ,GACZ,IAAI,CAON;AAED,wBAAgB,iBAAiB,CAAC,eAAe,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,MAAM,EAAE,CAUlF;AAED,wBAAgB,qBAAqB,CACnC,eAAe,EAAE,MAAM,EACvB,OAAO,GAAE,kBAAuB,EAChC,EAAE,CAAC,EAAE,QAAQ,GACZ,eAAe,CAAC,MAAM,CAAC,CAazB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,GAAG,OAAO,CAKhF;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,EACnC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,UAAU,GAAG,IAAI,GAAG,MAAM,GAAG,WAAW,CAAC,GACtE,OAAO,CAYT;AAED,wBAAgB,wBAAwB,CACtC,OAAO,GAAE,cAAuC,EAChD,EAAE,CAAC,EAAE,QAAQ,GACZ,OAAO,GAAG,IAAI,CAEhB;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,GAAE,cAAuC,EAChD,OAAO,GAAE,kBAAuB,EAChC,EAAE,CAAC,EAAE,QAAQ,GACZ,qBAAqB,CAwCvB"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from "./types/index.js";
|
|
2
2
|
export { CloudConfigStore, CloudHttpError, LocalConfigStore, isCloudMode, resolveCloudConfig, resolveConfigStore, } from "./data/config-store.js";
|
|
3
3
|
export type { CloudConfig, ConfigStore } from "./data/config-store.js";
|
|
4
|
+
export { boundedReadPage, normalizeBoundedReadOptions } from "./lib/bounded-read.js";
|
|
4
5
|
export { currentHostname, currentOs, currentArch } from "./db/machines.js";
|
|
5
6
|
export { uuid, now, slugify } from "./db/database.js";
|
|
6
7
|
export { getConfigsStatus } from "./status.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,kBAAkB,CAAC;AAIjC,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -596,6 +596,52 @@ function renderMachineAwareContentPreview(content, variables) {
|
|
|
596
596
|
return isTemplate(content) ? renderTemplatePreview(content, variables) : { content, unresolved: [] };
|
|
597
597
|
}
|
|
598
598
|
|
|
599
|
+
// src/lib/compact-output.ts
|
|
600
|
+
var DEFAULT_LIST_LIMIT = 20;
|
|
601
|
+
var MAX_LIST_LIMIT = 100;
|
|
602
|
+
function parseLimit(value, fallback = DEFAULT_LIST_LIMIT, max = MAX_LIST_LIMIT) {
|
|
603
|
+
const parsed = typeof value === "number" ? value : Number.parseInt(String(value ?? ""), 10);
|
|
604
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
605
|
+
return fallback;
|
|
606
|
+
return Math.min(Math.floor(parsed), max);
|
|
607
|
+
}
|
|
608
|
+
function parseCursor(value) {
|
|
609
|
+
const parsed = typeof value === "number" ? value : Number.parseInt(String(value ?? ""), 10);
|
|
610
|
+
if (!Number.isFinite(parsed) || parsed < 0)
|
|
611
|
+
return 0;
|
|
612
|
+
return Math.floor(parsed);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// src/lib/bounded-read.ts
|
|
616
|
+
function normalizeBoundedReadOptions(options = {}) {
|
|
617
|
+
return {
|
|
618
|
+
limit: parseLimit(options.limit, DEFAULT_LIST_LIMIT, MAX_LIST_LIMIT),
|
|
619
|
+
cursor: parseCursor(options.cursor)
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
function boundedReadPage(items, total, options = {}) {
|
|
623
|
+
const { limit, cursor } = normalizeBoundedReadOptions(options);
|
|
624
|
+
if (items.length > limit) {
|
|
625
|
+
throw new Error(`bounded read returned ${items.length} rows for limit ${limit}`);
|
|
626
|
+
}
|
|
627
|
+
const consumed = cursor + items.length;
|
|
628
|
+
const complete = consumed >= total;
|
|
629
|
+
if (!complete && items.length === 0) {
|
|
630
|
+
throw new Error(`bounded read did not advance at cursor ${cursor} of ${total}`);
|
|
631
|
+
}
|
|
632
|
+
return {
|
|
633
|
+
items,
|
|
634
|
+
total,
|
|
635
|
+
limit,
|
|
636
|
+
cursor,
|
|
637
|
+
next_cursor: complete ? null : consumed,
|
|
638
|
+
has_more: !complete,
|
|
639
|
+
complete,
|
|
640
|
+
truncated: false,
|
|
641
|
+
source_bounded: true
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
|
|
599
645
|
// src/db/profiles.ts
|
|
600
646
|
function rowToProfile(row) {
|
|
601
647
|
return {
|
|
@@ -639,9 +685,12 @@ function getProfile(idOrSlug, db) {
|
|
|
639
685
|
throw new ProfileNotFoundError(idOrSlug);
|
|
640
686
|
return rowToProfile(row);
|
|
641
687
|
}
|
|
642
|
-
function
|
|
688
|
+
function listProfilesPage(options = {}, db) {
|
|
643
689
|
const d = db || getDatabase();
|
|
644
|
-
|
|
690
|
+
const normalized = normalizeBoundedReadOptions(options);
|
|
691
|
+
const total = d.query("SELECT COUNT(*) AS total FROM profiles").get()?.total ?? 0;
|
|
692
|
+
const rows = d.query("SELECT * FROM profiles ORDER BY name LIMIT ? OFFSET ?").all(normalized.limit, normalized.cursor).map(rowToProfile);
|
|
693
|
+
return boundedReadPage(rows, total, normalized);
|
|
645
694
|
}
|
|
646
695
|
function updateProfile(idOrSlug, input, db) {
|
|
647
696
|
const d = db || getDatabase();
|
|
@@ -686,14 +735,13 @@ function removeConfigFromProfile(profileIdOrSlug, configId, db) {
|
|
|
686
735
|
const profile = getProfile(profileIdOrSlug, d);
|
|
687
736
|
d.run("DELETE FROM profile_configs WHERE profile_id = ? AND config_id = ?", [profile.id, configId]);
|
|
688
737
|
}
|
|
689
|
-
function
|
|
738
|
+
function getProfileConfigsPage(profileIdOrSlug, options = {}, db) {
|
|
690
739
|
const d = db || getDatabase();
|
|
691
740
|
const profile = getProfile(profileIdOrSlug, d);
|
|
692
|
-
const
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
return listConfigs(undefined, d).filter((c) => ids.includes(c.id));
|
|
741
|
+
const normalized = normalizeBoundedReadOptions(options);
|
|
742
|
+
const total = d.query("SELECT COUNT(*) AS total FROM profile_configs WHERE profile_id = ?").get(profile.id)?.total ?? 0;
|
|
743
|
+
const rows = d.query("SELECT config_id FROM profile_configs WHERE profile_id = ? ORDER BY sort_order LIMIT ? OFFSET ?").all(profile.id, normalized.limit, normalized.cursor);
|
|
744
|
+
return boundedReadPage(rows.map((row) => getConfigById(row.config_id, d)), total, normalized);
|
|
697
745
|
}
|
|
698
746
|
function profileHasSelectors(profile) {
|
|
699
747
|
const selectors = profile.selectors ?? {};
|
|
@@ -709,14 +757,39 @@ function profileMatchesMachine(profile, machine) {
|
|
|
709
757
|
const hostnameMatches = !selectors.hostnames?.length || selectors.hostnames.some((candidate) => candidate.trim().toLowerCase() === machine.hostname.trim().toLowerCase());
|
|
710
758
|
return osMatches && archMatches && hostnameMatches;
|
|
711
759
|
}
|
|
712
|
-
function
|
|
713
|
-
const
|
|
714
|
-
const
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
760
|
+
function resolveProfileForMachineRead(machine = detectMachineContext(), options = {}, db) {
|
|
761
|
+
const d = db || getDatabase();
|
|
762
|
+
const { limit } = normalizeBoundedReadOptions(options);
|
|
763
|
+
let cursor = 0;
|
|
764
|
+
let scanned = 0;
|
|
765
|
+
let total = 0;
|
|
766
|
+
let selected = null;
|
|
767
|
+
while (true) {
|
|
768
|
+
const page = listProfilesPage({ limit, cursor }, d);
|
|
769
|
+
total = page.total;
|
|
770
|
+
scanned += page.items.length;
|
|
771
|
+
for (const profile of page.items) {
|
|
772
|
+
if (!profileHasSelectors(profile) || !profileMatchesMachine(profile, machine))
|
|
773
|
+
continue;
|
|
774
|
+
const selectors = profile.selectors;
|
|
775
|
+
const score = (selectors.hostnames?.length ? 100 : 0) + (selectors.os?.length ? 10 : 0) + (selectors.arch?.length ? 10 : 0);
|
|
776
|
+
if (!selected || score > selected.score || score === selected.score && profile.name.localeCompare(selected.profile.name) < 0) {
|
|
777
|
+
selected = { profile, score };
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
if (page.complete)
|
|
781
|
+
break;
|
|
782
|
+
cursor = page.next_cursor;
|
|
783
|
+
}
|
|
784
|
+
return {
|
|
785
|
+
profile: selected?.profile ?? null,
|
|
786
|
+
scanned,
|
|
787
|
+
total,
|
|
788
|
+
batch_limit: limit,
|
|
789
|
+
source_bounded: true,
|
|
790
|
+
complete: true,
|
|
791
|
+
truncated: false
|
|
792
|
+
};
|
|
720
793
|
}
|
|
721
794
|
|
|
722
795
|
// src/db/snapshots.ts
|
|
@@ -797,6 +870,32 @@ class CloudHttpError extends Error {
|
|
|
797
870
|
this.name = "CloudHttpError";
|
|
798
871
|
}
|
|
799
872
|
}
|
|
873
|
+
function parseBoundedPagePayload(value, label) {
|
|
874
|
+
const page = value;
|
|
875
|
+
const consumed = Number(page?.cursor) + (page?.items?.length ?? 0);
|
|
876
|
+
const complete = Boolean(page && Number.isSafeInteger(page.total) && consumed >= Number(page.total));
|
|
877
|
+
if (!page || !Array.isArray(page.items) || !Number.isSafeInteger(page.total) || Number(page.total) < 0 || !Number.isSafeInteger(page.limit) || Number(page.limit) < 1 || !Number.isSafeInteger(page.cursor) || Number(page.cursor) < 0 || page.items.length > Number(page.limit) || typeof page.has_more !== "boolean" || typeof page.complete !== "boolean" || page.truncated !== false || page.next_cursor !== null && !Number.isSafeInteger(page.next_cursor) || page.complete !== complete || page.has_more !== !complete || page.next_cursor !== (complete ? null : consumed)) {
|
|
878
|
+
throw new CloudHttpError(502, `${label} returned an invalid or truncated bounded-read envelope`, value);
|
|
879
|
+
}
|
|
880
|
+
return {
|
|
881
|
+
...page,
|
|
882
|
+
source_bounded: page.source_bounded ?? true
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
function parseBoundedOrLegacyPage(value, legacyItems, options, label) {
|
|
886
|
+
if (value && typeof value === "object") {
|
|
887
|
+
const candidate = value;
|
|
888
|
+
if ("items" in candidate || "total" in candidate || "complete" in candidate || "truncated" in candidate || "next_cursor" in candidate) {
|
|
889
|
+
return parseBoundedPagePayload(value, label);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
if (!Array.isArray(legacyItems)) {
|
|
893
|
+
throw new CloudHttpError(502, `${label} returned neither a bounded envelope nor a complete legacy array`, value);
|
|
894
|
+
}
|
|
895
|
+
const normalized = normalizeBoundedReadOptions(options);
|
|
896
|
+
const page = boundedReadPage(legacyItems.slice(normalized.cursor, normalized.cursor + normalized.limit), legacyItems.length, normalized);
|
|
897
|
+
return { ...page, source_bounded: false };
|
|
898
|
+
}
|
|
800
899
|
var API_URL_ENV = "HASNA_INSTRUCTIONS_API_URL";
|
|
801
900
|
var API_KEY_ENV = "HASNA_INSTRUCTIONS_API_KEY";
|
|
802
901
|
function resolveCloudConfig(env = process.env) {
|
|
@@ -856,13 +955,35 @@ class LocalConfigStore {
|
|
|
856
955
|
return pruneSnapshots(configId, keep, this.db);
|
|
857
956
|
}
|
|
858
957
|
async listProfiles() {
|
|
859
|
-
|
|
958
|
+
const profiles = [];
|
|
959
|
+
let cursor = 0;
|
|
960
|
+
while (true) {
|
|
961
|
+
const page = await this.listProfilesPage({ limit: 100, cursor });
|
|
962
|
+
profiles.push(...page.items);
|
|
963
|
+
if (page.complete)
|
|
964
|
+
return profiles;
|
|
965
|
+
cursor = page.next_cursor;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
async listProfilesPage(options = {}) {
|
|
969
|
+
return listProfilesPage(options, this.db);
|
|
860
970
|
}
|
|
861
971
|
async getProfile(idOrSlug) {
|
|
862
972
|
return getProfile(idOrSlug, this.db);
|
|
863
973
|
}
|
|
864
974
|
async getProfileConfigs(idOrSlug) {
|
|
865
|
-
|
|
975
|
+
const configs = [];
|
|
976
|
+
let cursor = 0;
|
|
977
|
+
while (true) {
|
|
978
|
+
const page = await this.getProfileConfigsPage(idOrSlug, { limit: 100, cursor });
|
|
979
|
+
configs.push(...page.items);
|
|
980
|
+
if (page.complete)
|
|
981
|
+
return configs;
|
|
982
|
+
cursor = page.next_cursor;
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
async getProfileConfigsPage(idOrSlug, options = {}) {
|
|
986
|
+
return getProfileConfigsPage(idOrSlug, options, this.db);
|
|
866
987
|
}
|
|
867
988
|
async createProfile(input) {
|
|
868
989
|
return createProfile(input, this.db);
|
|
@@ -880,7 +1001,10 @@ class LocalConfigStore {
|
|
|
880
1001
|
removeConfigFromProfile(profileIdOrSlug, configId, this.db);
|
|
881
1002
|
}
|
|
882
1003
|
async resolveProfileForMachine(machine) {
|
|
883
|
-
return
|
|
1004
|
+
return (await this.resolveProfileForMachineRead(machine)).profile;
|
|
1005
|
+
}
|
|
1006
|
+
async resolveProfileForMachineRead(machine, options = {}) {
|
|
1007
|
+
return machine ? resolveProfileForMachineRead(machine, options, this.db) : resolveProfileForMachineRead(undefined, options, this.db);
|
|
884
1008
|
}
|
|
885
1009
|
async registerMachine(hostname2, os, arch2) {
|
|
886
1010
|
return registerMachine(hostname2, os, arch2, this.db);
|
|
@@ -1021,8 +1145,24 @@ class CloudConfigStore {
|
|
|
1021
1145
|
return data?.pruned ?? 0;
|
|
1022
1146
|
}
|
|
1023
1147
|
async listProfiles() {
|
|
1024
|
-
const
|
|
1025
|
-
|
|
1148
|
+
const profiles = [];
|
|
1149
|
+
let cursor = 0;
|
|
1150
|
+
while (true) {
|
|
1151
|
+
const page = await this.listProfilesPage({ limit: 100, cursor });
|
|
1152
|
+
profiles.push(...page.items);
|
|
1153
|
+
if (page.complete)
|
|
1154
|
+
return profiles;
|
|
1155
|
+
cursor = page.next_cursor;
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
async listProfilesPage(options = {}) {
|
|
1159
|
+
const normalized = normalizeBoundedReadOptions(options);
|
|
1160
|
+
const params = new URLSearchParams;
|
|
1161
|
+
params.set("limit", String(normalized.limit));
|
|
1162
|
+
params.set("cursor", String(normalized.cursor));
|
|
1163
|
+
const qs = params.toString();
|
|
1164
|
+
const { data } = await this.request("GET", `/profiles${qs ? `?${qs}` : ""}`);
|
|
1165
|
+
return parseBoundedOrLegacyPage(data, data?.profiles, normalized, "profile list");
|
|
1026
1166
|
}
|
|
1027
1167
|
async getProfile(idOrSlug) {
|
|
1028
1168
|
const { status, data } = await this.request("GET", `/profiles/${encodeURIComponent(idOrSlug)}`, undefined, { allow404: true });
|
|
@@ -1032,10 +1172,26 @@ class CloudConfigStore {
|
|
|
1032
1172
|
return profile;
|
|
1033
1173
|
}
|
|
1034
1174
|
async getProfileConfigs(idOrSlug) {
|
|
1035
|
-
const
|
|
1175
|
+
const configs = [];
|
|
1176
|
+
let cursor = 0;
|
|
1177
|
+
while (true) {
|
|
1178
|
+
const page = await this.getProfileConfigsPage(idOrSlug, { limit: 100, cursor });
|
|
1179
|
+
configs.push(...page.items);
|
|
1180
|
+
if (page.complete)
|
|
1181
|
+
return configs;
|
|
1182
|
+
cursor = page.next_cursor;
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
async getProfileConfigsPage(idOrSlug, options = {}) {
|
|
1186
|
+
const normalized = normalizeBoundedReadOptions(options);
|
|
1187
|
+
const params = new URLSearchParams;
|
|
1188
|
+
params.set("limit", String(normalized.limit));
|
|
1189
|
+
params.set("cursor", String(normalized.cursor));
|
|
1190
|
+
const qs = params.toString();
|
|
1191
|
+
const { status, data } = await this.request("GET", `/profiles/${encodeURIComponent(idOrSlug)}${qs ? `?${qs}` : ""}`, undefined, { allow404: true });
|
|
1036
1192
|
if (status === 404 || !data?.profile)
|
|
1037
1193
|
throw new ProfileNotFoundError(idOrSlug);
|
|
1038
|
-
return data.profile.configs
|
|
1194
|
+
return parseBoundedOrLegacyPage(data.configs, data.profile.configs, normalized, "profile membership");
|
|
1039
1195
|
}
|
|
1040
1196
|
async createProfile(input) {
|
|
1041
1197
|
const { data } = await this.request("POST", "/profiles", input, {
|
|
@@ -1059,6 +1215,10 @@ class CloudConfigStore {
|
|
|
1059
1215
|
await this.request("DELETE", `/profiles/${encodeURIComponent(profileIdOrSlug)}/configs/${encodeURIComponent(configId)}`, undefined, { allow404: true });
|
|
1060
1216
|
}
|
|
1061
1217
|
async resolveProfileForMachine(machine) {
|
|
1218
|
+
return (await this.resolveProfileForMachineRead(machine)).profile;
|
|
1219
|
+
}
|
|
1220
|
+
async resolveProfileForMachineRead(machine, options = {}) {
|
|
1221
|
+
const normalized = normalizeBoundedReadOptions(options);
|
|
1062
1222
|
const params = new URLSearchParams;
|
|
1063
1223
|
if (machine?.hostname)
|
|
1064
1224
|
params.set("hostname", machine.hostname);
|
|
@@ -1066,11 +1226,40 @@ class CloudConfigStore {
|
|
|
1066
1226
|
params.set("os", machine.os);
|
|
1067
1227
|
if (machine?.arch)
|
|
1068
1228
|
params.set("arch", machine.arch);
|
|
1229
|
+
params.set("limit", String(normalized.limit));
|
|
1069
1230
|
const qs = params.toString();
|
|
1070
1231
|
const { status, data } = await this.request("GET", `/profiles/resolve${qs ? `?${qs}` : ""}`, undefined, { allow404: true });
|
|
1071
|
-
if (status === 404
|
|
1072
|
-
return
|
|
1073
|
-
|
|
1232
|
+
if (status === 404) {
|
|
1233
|
+
return {
|
|
1234
|
+
profile: null,
|
|
1235
|
+
scanned: null,
|
|
1236
|
+
total: null,
|
|
1237
|
+
batch_limit: null,
|
|
1238
|
+
source_bounded: false,
|
|
1239
|
+
complete: true,
|
|
1240
|
+
truncated: false
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
if (data && "complete" in data) {
|
|
1244
|
+
if (data.complete !== true || data.truncated !== false) {
|
|
1245
|
+
throw new CloudHttpError(502, "profile resolve returned an incomplete or truncated read", data);
|
|
1246
|
+
}
|
|
1247
|
+
return { ...data, source_bounded: data.source_bounded ?? true };
|
|
1248
|
+
}
|
|
1249
|
+
if (data && "profile" in data) {
|
|
1250
|
+
return {
|
|
1251
|
+
profile: data.profile,
|
|
1252
|
+
scanned: null,
|
|
1253
|
+
total: null,
|
|
1254
|
+
batch_limit: null,
|
|
1255
|
+
source_bounded: false,
|
|
1256
|
+
complete: true,
|
|
1257
|
+
truncated: false
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
{
|
|
1261
|
+
throw new CloudHttpError(502, "profile resolve returned an incomplete or truncated read", data);
|
|
1262
|
+
}
|
|
1074
1263
|
}
|
|
1075
1264
|
async registerMachine(hostname2, os, arch2) {
|
|
1076
1265
|
const { data } = await this.request("POST", "/machines", { hostname: hostname2, os, arch: arch2 }, { idempotent: true });
|
|
@@ -11251,7 +11440,7 @@ var PROJECT_DASHBOARD_PROFILE_VARIABLES = {
|
|
|
11251
11440
|
PROJECT_DASHBOARD_DIR: ".hasna/project",
|
|
11252
11441
|
PROJECT_DASHBOARD_RENDER_MANIFEST: ".hasna/project/dashboard/render.json",
|
|
11253
11442
|
PROJECT_DASHBOARD_SNAPSHOTS_DIR: ".hasna/project/dashboard/snapshots",
|
|
11254
|
-
PROJECT_CHANNEL_PREFIX: "
|
|
11443
|
+
PROJECT_CHANNEL_PREFIX: ""
|
|
11255
11444
|
};
|
|
11256
11445
|
var PROJECT_DASHBOARD_STANDARD_CONTENT = `# Agent-Managed Project Dashboard Standard
|
|
11257
11446
|
|
|
@@ -11306,8 +11495,8 @@ context.
|
|
|
11306
11495
|
|
|
11307
11496
|
## Coordination
|
|
11308
11497
|
|
|
11309
|
-
- Project conversation channels use
|
|
11310
|
-
displayed to humans as
|
|
11498
|
+
- Project conversation channels use the normalized project slug in the CLI and
|
|
11499
|
+
are displayed to humans as \`#<project-slug>\`.
|
|
11311
11500
|
- Todos tasks are the source of truth for work; messages are only coordination.
|
|
11312
11501
|
- Durable Codewith goal plans should own long-running implementation.
|
|
11313
11502
|
- New implementation/verification work should route through task-triggered fresh
|
|
@@ -11412,10 +11601,15 @@ function mergeProfileSelectors(preset, existing) {
|
|
|
11412
11601
|
};
|
|
11413
11602
|
}
|
|
11414
11603
|
function mergeProfileVariables(preset, existing) {
|
|
11415
|
-
|
|
11604
|
+
const variables = {
|
|
11416
11605
|
...preset ?? {},
|
|
11417
11606
|
...existing
|
|
11418
11607
|
};
|
|
11608
|
+
for (const [key, value] of Object.entries(preset ?? {})) {
|
|
11609
|
+
if (value === "")
|
|
11610
|
+
variables[key] = value;
|
|
11611
|
+
}
|
|
11612
|
+
return variables;
|
|
11419
11613
|
}
|
|
11420
11614
|
function mergeUnique(preset, existing) {
|
|
11421
11615
|
const values = [...new Set([...preset ?? [], ...existing ?? []])];
|
|
@@ -12650,6 +12844,7 @@ export {
|
|
|
12650
12844
|
parseAgentOperatingRulesVersion,
|
|
12651
12845
|
now,
|
|
12652
12846
|
normalizeOsFamily,
|
|
12847
|
+
normalizeBoundedReadOptions,
|
|
12653
12848
|
machineContextToVariables,
|
|
12654
12849
|
isTemplate,
|
|
12655
12850
|
isCloudMode,
|
|
@@ -12679,6 +12874,7 @@ export {
|
|
|
12679
12874
|
buildOpenCodeAgentsMd,
|
|
12680
12875
|
buildCursorMdc,
|
|
12681
12876
|
buildCodexAgentsMd,
|
|
12877
|
+
boundedReadPage,
|
|
12682
12878
|
applyTransform,
|
|
12683
12879
|
applySessionRender,
|
|
12684
12880
|
applyProjectContext,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { BoundedReadOptions, BoundedReadPage } from "../types/index.js";
|
|
2
|
+
export declare function normalizeBoundedReadOptions(options?: BoundedReadOptions): {
|
|
3
|
+
limit: number;
|
|
4
|
+
cursor: number;
|
|
5
|
+
};
|
|
6
|
+
export declare function boundedReadPage<T>(items: T[], total: number, options?: BoundedReadOptions): BoundedReadPage<T>;
|
|
7
|
+
//# sourceMappingURL=bounded-read.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bounded-read.d.ts","sourceRoot":"","sources":["../../src/lib/bounded-read.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAE7E,wBAAgB,2BAA2B,CACzC,OAAO,GAAE,kBAAuB,GAC/B;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAKnC;AAED,wBAAgB,eAAe,CAAC,CAAC,EAC/B,KAAK,EAAE,CAAC,EAAE,EACV,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,kBAAuB,GAC/B,eAAe,CAAC,CAAC,CAAC,CAqBpB"}
|
|
@@ -15,6 +15,82 @@ import type { Config } from "../types/index.js";
|
|
|
15
15
|
* Reference configs (`kind: "reference"`) own no target path and never match.
|
|
16
16
|
*/
|
|
17
17
|
export declare function findConfigsByTargetPath(configs: Config[], targetPath: string): Config[];
|
|
18
|
+
/**
|
|
19
|
+
* Every reference-kind row already ingested under `name`.
|
|
20
|
+
*
|
|
21
|
+
* A reference config (`kind: "reference"`) owns no target_path — it is not
|
|
22
|
+
* mirrored 1:1 onto one file on disk, so `findConfigsByTargetPath` can never
|
|
23
|
+
* find it, by design (see that function's own doc comment). That left
|
|
24
|
+
* `add <path> --kind reference --update` with no identity signal at all: every
|
|
25
|
+
* re-ingest of a reference config's content minted a fresh row instead of
|
|
26
|
+
* updating the one that already existed, at every `--update` setting, because
|
|
27
|
+
* there was nothing to match on. Measured live 2026-08-04, todos 757cefdb: 20
|
|
28
|
+
* of 20 reference-kind rows in the fleet store had target_path=null.
|
|
29
|
+
*
|
|
30
|
+
* For a reference config, `name` IS the identity, in exactly the same sense a
|
|
31
|
+
* file-kind config's target_path is its identity: re-ingest with the same
|
|
32
|
+
* name, get the same row; re-ingest with a different name, get a different
|
|
33
|
+
* (or new) row. Two comparisons, both needed:
|
|
34
|
+
*
|
|
35
|
+
* - EXACT name match. `uniqueSlug` (db/database.ts) only de-duplicates the
|
|
36
|
+
* SLUG column, which carries a DB-level UNIQUE constraint — it never
|
|
37
|
+
* touches `name`, which carries no such constraint. So every prior
|
|
38
|
+
* duplicate this bug already produced still has the identical `name` and a
|
|
39
|
+
* `-1`, `-2`, ... suffixed slug. Measured live 2026-08-04 in the fleet
|
|
40
|
+
* store: 8 reference rows all named "Global Agent Rules Standard"
|
|
41
|
+
* (`global-agent-rules-standard-1` through `-8`), one identical SHA-256
|
|
42
|
+
* content hash across all 8, ingested on 6 different days — the exact
|
|
43
|
+
* shape this function exists to stop.
|
|
44
|
+
* - Slugified match, for a re-ingest whose `--name` differs only in case or
|
|
45
|
+
* punctuation from an existing row's name.
|
|
46
|
+
*
|
|
47
|
+
* CORRECTED 2026-08-04 (todos 195272ae, Finding 1): this used to compare
|
|
48
|
+
* the query's slug against each candidate's STORED `.slug` COLUMN
|
|
49
|
+
* (`config.slug === wantedSlug`). That is sound only for a candidate whose
|
|
50
|
+
* own slug was never disambiguated — the moment two rows already collide
|
|
51
|
+
* and `uniqueSlug` has suffixed one of them (`sample-rule-1`), its stored
|
|
52
|
+
* slug no longer equals what re-slugifying its OWN name produces, so the
|
|
53
|
+
* old comparison went blind to it. Reproduced live: row A "Sample Rule"
|
|
54
|
+
* (slug "sample-rule"), row B "sample rule" (slug disambiguated to
|
|
55
|
+
* "sample-rule-1" because A already held the base slug) — querying "Sample
|
|
56
|
+
* Rule" found only A. `add --update` then updated A, reported
|
|
57
|
+
* `rest.length === 0` (no "N other rows share this name" warning), and
|
|
58
|
+
* left B — the exact row a human would call a duplicate of A — untouched
|
|
59
|
+
* and unmentioned. This is the one population the slug clause exists to
|
|
60
|
+
* catch: it is impossible for a fresh, non-colliding row to need it, since
|
|
61
|
+
* an un-disambiguated slug already matches via `slugify(name)` trivially.
|
|
62
|
+
* Comparing against `slugify(config.name)` instead — recomputed from the
|
|
63
|
+
* candidate's own name rather than trusted from its (possibly
|
|
64
|
+
* disambiguated) stored column — fixes this without weakening the EXACT
|
|
65
|
+
* name clause above, which still independently catches the byte-identical
|
|
66
|
+
* case regardless: it can only ADD matches the old comparison missed, not
|
|
67
|
+
* remove any a query's name literally shares.
|
|
68
|
+
*/
|
|
69
|
+
export declare function findReferenceConfigsByName(configs: Config[], name: string): Config[];
|
|
70
|
+
/**
|
|
71
|
+
* Groups of reference-kind rows that collide on identity, the mirror image of
|
|
72
|
+
* `findDuplicateTargetPathGroups` for the identity axis reference configs
|
|
73
|
+
* actually use. Only groups with more than one member are returned, so an
|
|
74
|
+
* empty result means the store is clean.
|
|
75
|
+
*
|
|
76
|
+
* CORRECTED 2026-08-04 (todos 195272ae, Finding 1): grouping used to key on
|
|
77
|
+
* the raw, exact `config.name` string. `doctor` (which calls this) therefore
|
|
78
|
+
* reported a store CLEAN for two rows whose names differ only in case or
|
|
79
|
+
* punctuation — precisely the pair `findReferenceConfigsByName` above treats
|
|
80
|
+
* as one identity (see its doc comment for the reproduction). The two
|
|
81
|
+
* functions disagreeing about what "the same reference config" means was the
|
|
82
|
+
* same defect class PR #57 fixed one level up, one file down: `doctor` a
|
|
83
|
+
* store clean, `add --update` half-fixing it. Keying on `slugify(config.name)`
|
|
84
|
+
* instead makes this agree with `findReferenceConfigsByName`'s identity
|
|
85
|
+
* notion — a case/punctuation variant is now reported as a duplicate group
|
|
86
|
+
* too, not only a byte-identical one. The reported `name` is the first
|
|
87
|
+
* colliding row's own (human-authored) name, for display — the grouping key
|
|
88
|
+
* itself is never surfaced.
|
|
89
|
+
*/
|
|
90
|
+
export declare function findDuplicateReferenceNameGroups(configs: Config[]): Array<{
|
|
91
|
+
name: string;
|
|
92
|
+
configs: Config[];
|
|
93
|
+
}>;
|
|
18
94
|
/**
|
|
19
95
|
* Groups of rows that collide on one normalized target path. Only groups with
|
|
20
96
|
* more than one member are returned, so an empty result means the store is
|