ai-ops-cli 1.3.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/index.js
CHANGED
|
@@ -363,6 +363,156 @@ var PackCatalogSchema = z10.object({
|
|
|
363
363
|
packs: z10.array(PackCatalogEntrySchema)
|
|
364
364
|
}).strict();
|
|
365
365
|
|
|
366
|
+
// src/core/schemas/studio-snapshot.schema.ts
|
|
367
|
+
import { z as z11 } from "zod";
|
|
368
|
+
var nullableString = z11.string().nullable();
|
|
369
|
+
var StudioProjectStateSchema = z11.union([
|
|
370
|
+
z11.literal("ready"),
|
|
371
|
+
z11.literal("uninitialized"),
|
|
372
|
+
z11.literal("degraded")
|
|
373
|
+
]);
|
|
374
|
+
var StudioProjectDocumentProvenanceSchema = z11.union([
|
|
375
|
+
z11.literal("ai-ops-managed"),
|
|
376
|
+
z11.literal("project-owned"),
|
|
377
|
+
z11.literal("pack-document"),
|
|
378
|
+
z11.literal("context-only")
|
|
379
|
+
]);
|
|
380
|
+
var StudioRuntimeFileStateSchema = z11.object({
|
|
381
|
+
path: z11.string().min(1),
|
|
382
|
+
exists: z11.boolean()
|
|
383
|
+
}).strict();
|
|
384
|
+
var StudioSourceStateSchema = z11.object({
|
|
385
|
+
path: z11.string().min(1),
|
|
386
|
+
exists: z11.boolean(),
|
|
387
|
+
parsed: z11.boolean(),
|
|
388
|
+
generatedAt: nullableString,
|
|
389
|
+
error: nullableString
|
|
390
|
+
}).strict();
|
|
391
|
+
var StudioProjectIssueSourceSchema = z11.union([
|
|
392
|
+
z11.literal("manifest"),
|
|
393
|
+
z11.literal("context-layer"),
|
|
394
|
+
z11.literal("docs-status"),
|
|
395
|
+
z11.literal("frontmatter"),
|
|
396
|
+
z11.literal("managed-section"),
|
|
397
|
+
z11.literal("file-system"),
|
|
398
|
+
z11.literal("source-hash"),
|
|
399
|
+
z11.literal("unknown")
|
|
400
|
+
]);
|
|
401
|
+
var StudioProjectIssueSchema = z11.object({
|
|
402
|
+
level: z11.union([z11.literal("error"), z11.literal("warning")]),
|
|
403
|
+
code: z11.string().min(1),
|
|
404
|
+
message: z11.string().min(1),
|
|
405
|
+
source: StudioProjectIssueSourceSchema,
|
|
406
|
+
affectedPath: nullableString,
|
|
407
|
+
suggestedActionLabel: nullableString
|
|
408
|
+
}).strict();
|
|
409
|
+
var StudioProjectDocumentSchema = z11.object({
|
|
410
|
+
path: z11.string().min(1),
|
|
411
|
+
status: ProjectLayerDocumentStatusSchema,
|
|
412
|
+
layer: z11.string().min(1),
|
|
413
|
+
owner: z11.string().min(1),
|
|
414
|
+
read_when: z11.array(z11.string().min(1)),
|
|
415
|
+
update_when: z11.array(z11.string().min(1)),
|
|
416
|
+
indexedContentHash: z11.string().min(1),
|
|
417
|
+
currentContentHash: nullableString,
|
|
418
|
+
contentHashMatches: z11.boolean().nullable(),
|
|
419
|
+
provenance: StudioProjectDocumentProvenanceSchema,
|
|
420
|
+
content: nullableString,
|
|
421
|
+
trustWarning: nullableString,
|
|
422
|
+
readError: nullableString
|
|
423
|
+
}).strict();
|
|
424
|
+
var StudioProjectSnapshotSchema = z11.object({
|
|
425
|
+
root: z11.string().min(1),
|
|
426
|
+
state: StudioProjectStateSchema,
|
|
427
|
+
files: z11.object({
|
|
428
|
+
manifest: StudioSourceStateSchema,
|
|
429
|
+
contextIndex: StudioSourceStateSchema,
|
|
430
|
+
docsStatus: StudioSourceStateSchema
|
|
431
|
+
}).strict(),
|
|
432
|
+
audit: z11.object({
|
|
433
|
+
currentSourceHash: nullableString,
|
|
434
|
+
hasErrors: z11.boolean(),
|
|
435
|
+
hasWarnings: z11.boolean(),
|
|
436
|
+
issues: z11.array(StudioProjectIssueSchema)
|
|
437
|
+
}).strict(),
|
|
438
|
+
documents: z11.array(StudioProjectDocumentSchema)
|
|
439
|
+
}).strict();
|
|
440
|
+
var StudioIntegrationComponentStatusSchema = z11.object({
|
|
441
|
+
type: z11.union([
|
|
442
|
+
z11.literal(INTEGRATION_COMPONENT_TYPE.SKILL),
|
|
443
|
+
z11.literal(INTEGRATION_COMPONENT_TYPE.CODEX_HOOK),
|
|
444
|
+
z11.literal(INTEGRATION_COMPONENT_TYPE.RECEIPT_CONFIG)
|
|
445
|
+
]),
|
|
446
|
+
id: z11.string().min(1),
|
|
447
|
+
installed: z11.boolean(),
|
|
448
|
+
owned: z11.boolean().nullable(),
|
|
449
|
+
catalog: IntegrationCatalogComponentSchema,
|
|
450
|
+
installedComponent: IntegrationComponentSchema.nullable()
|
|
451
|
+
}).strict();
|
|
452
|
+
var StudioIntegrationSnapshotSchema = z11.object({
|
|
453
|
+
id: IntegrationIdSchema,
|
|
454
|
+
description: z11.string().min(1),
|
|
455
|
+
installed: z11.boolean(),
|
|
456
|
+
installedAt: nullableString,
|
|
457
|
+
updatedAt: nullableString,
|
|
458
|
+
components: z11.array(StudioIntegrationComponentStatusSchema)
|
|
459
|
+
}).strict();
|
|
460
|
+
var StudioInstalledPathStateSchema = z11.object({
|
|
461
|
+
path: z11.string().min(1),
|
|
462
|
+
exists: z11.boolean()
|
|
463
|
+
}).strict();
|
|
464
|
+
var StudioSkillSnapshotSchema = z11.object({
|
|
465
|
+
id: z11.string().min(1),
|
|
466
|
+
kind: SkillKindSchema,
|
|
467
|
+
description: z11.string().min(1),
|
|
468
|
+
supported_tools: z11.array(SkillToolSchema),
|
|
469
|
+
groups: z11.array(z11.string().min(1)),
|
|
470
|
+
installed: z11.boolean(),
|
|
471
|
+
installedTools: z11.array(SkillToolSchema),
|
|
472
|
+
installedPaths: z11.array(StudioInstalledPathStateSchema),
|
|
473
|
+
sourceHash: nullableString
|
|
474
|
+
}).strict();
|
|
475
|
+
var StudioSubagentSnapshotSchema = z11.object({
|
|
476
|
+
id: SubagentIdSchema,
|
|
477
|
+
description: z11.string().min(1),
|
|
478
|
+
supported_tools: z11.array(SkillToolSchema),
|
|
479
|
+
installed: z11.boolean(),
|
|
480
|
+
installedTools: z11.array(SkillToolSchema),
|
|
481
|
+
installedPaths: z11.array(StudioInstalledPathStateSchema),
|
|
482
|
+
sourceHash: nullableString
|
|
483
|
+
}).strict();
|
|
484
|
+
var StudioHookSnapshotSchema = z11.object({
|
|
485
|
+
id: z11.string().min(1),
|
|
486
|
+
statusMessage: z11.string().min(1),
|
|
487
|
+
hooksPath: nullableString,
|
|
488
|
+
installed: z11.boolean(),
|
|
489
|
+
error: nullableString
|
|
490
|
+
}).strict();
|
|
491
|
+
var StudioRuntimeSnapshotSchema = z11.object({
|
|
492
|
+
available: z11.boolean(),
|
|
493
|
+
unavailableReason: nullableString,
|
|
494
|
+
userBasePath: nullableString,
|
|
495
|
+
codexHomePath: nullableString,
|
|
496
|
+
manifests: z11.object({
|
|
497
|
+
integrations: StudioSourceStateSchema,
|
|
498
|
+
skills: StudioSourceStateSchema,
|
|
499
|
+
subagents: StudioSourceStateSchema,
|
|
500
|
+
hooks: StudioSourceStateSchema
|
|
501
|
+
}).strict(),
|
|
502
|
+
integrations: z11.array(StudioIntegrationSnapshotSchema),
|
|
503
|
+
skills: z11.array(StudioSkillSnapshotSchema),
|
|
504
|
+
subagents: z11.array(StudioSubagentSnapshotSchema),
|
|
505
|
+
hooks: z11.array(StudioHookSnapshotSchema)
|
|
506
|
+
}).strict();
|
|
507
|
+
var StudioSnapshotSchema = z11.object({
|
|
508
|
+
schemaVersion: z11.literal(1),
|
|
509
|
+
kind: z11.literal("ai-ops-studio-snapshot"),
|
|
510
|
+
generatedAt: z11.string().datetime({ offset: true }),
|
|
511
|
+
cliVersion: z11.string().min(1),
|
|
512
|
+
project: StudioProjectSnapshotSchema,
|
|
513
|
+
runtime: StudioRuntimeSnapshotSchema
|
|
514
|
+
}).strict();
|
|
515
|
+
|
|
366
516
|
// src/core/loader.ts
|
|
367
517
|
import { readFileSync, readdirSync } from "fs";
|
|
368
518
|
import { join as join2, resolve } from "path";
|
|
@@ -1576,24 +1726,914 @@ var removeEmptyDirs = (basePath, relativePaths) => {
|
|
|
1576
1726
|
}
|
|
1577
1727
|
}
|
|
1578
1728
|
};
|
|
1579
|
-
var uninstallProjectLayer = (basePath, manifest) => {
|
|
1580
|
-
const managedResults = manifest.managed_files.map((file) => removeManagedProjectFile(basePath, file.path));
|
|
1581
|
-
const projectResults = manifest.project_files.map((file) => removeCreateOnlyProjectFile(basePath, file));
|
|
1582
|
-
const packResults = manifest.packs.flatMap(
|
|
1583
|
-
(pack) => [...pack.documents, ...pack.files].map((file) => removePackOwnedFile(basePath, file))
|
|
1584
|
-
);
|
|
1585
|
-
const stateFiles = [PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH, PROJECT_LAYER_MANIFEST_RELATIVE_PATH];
|
|
1586
|
-
for (const stateFile of stateFiles) {
|
|
1587
|
-
rmSync2(resolveProjectLayerFilePath(basePath, stateFile), { force: true });
|
|
1729
|
+
var uninstallProjectLayer = (basePath, manifest) => {
|
|
1730
|
+
const managedResults = manifest.managed_files.map((file) => removeManagedProjectFile(basePath, file.path));
|
|
1731
|
+
const projectResults = manifest.project_files.map((file) => removeCreateOnlyProjectFile(basePath, file));
|
|
1732
|
+
const packResults = manifest.packs.flatMap(
|
|
1733
|
+
(pack) => [...pack.documents, ...pack.files].map((file) => removePackOwnedFile(basePath, file))
|
|
1734
|
+
);
|
|
1735
|
+
const stateFiles = [PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH, PROJECT_LAYER_MANIFEST_RELATIVE_PATH];
|
|
1736
|
+
for (const stateFile of stateFiles) {
|
|
1737
|
+
rmSync2(resolveProjectLayerFilePath(basePath, stateFile), { force: true });
|
|
1738
|
+
}
|
|
1739
|
+
const result = mergeRemoveResults([...managedResults, ...projectResults, ...packResults]);
|
|
1740
|
+
removeEmptyDirs(basePath, [...result.deleted, ...stateFiles]);
|
|
1741
|
+
return result;
|
|
1742
|
+
};
|
|
1743
|
+
|
|
1744
|
+
// src/core/studio-snapshot.ts
|
|
1745
|
+
import { existsSync as existsSync3, readFileSync as readFileSync8 } from "fs";
|
|
1746
|
+
import { join as join10, resolve as resolve6 } from "path";
|
|
1747
|
+
import { z as z12 } from "zod";
|
|
1748
|
+
|
|
1749
|
+
// src/core/codex-hook.ts
|
|
1750
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
1751
|
+
import { dirname as dirname7, join as join9 } from "path";
|
|
1752
|
+
var CONTEXT_PROMOTION_HOOK_ID = "context-promotion";
|
|
1753
|
+
var CONTEXT_PROMOTION_HOOK_COMMAND_MARKER = "context-promotion hook post-tool-use";
|
|
1754
|
+
var CONTEXT_PROMOTION_LEGACY_HOOK_COMMAND_MARKER = "context-promotion hook pre-tool-use";
|
|
1755
|
+
var CONTEXT_PROMOTION_DEFAULT_HOOK_COMMAND = `ai-ops ${CONTEXT_PROMOTION_HOOK_COMMAND_MARKER}`;
|
|
1756
|
+
var PC_HOOK_ID = "pc";
|
|
1757
|
+
var PC_HOOK_COMMAND_MARKER = "integration hook post-tool-use pc";
|
|
1758
|
+
var PC_DEFAULT_HOOK_COMMAND = `ai-ops ${PC_HOOK_COMMAND_MARKER}`;
|
|
1759
|
+
var PRE_TOOL_USE_EVENT = "PreToolUse";
|
|
1760
|
+
var POST_TOOL_USE_EVENT = "PostToolUse";
|
|
1761
|
+
var BASH_MATCHER = "^Bash$";
|
|
1762
|
+
var CONTEXT_PROMOTION_CODEX_HOOK = {
|
|
1763
|
+
id: CONTEXT_PROMOTION_HOOK_ID,
|
|
1764
|
+
commandMarker: CONTEXT_PROMOTION_HOOK_COMMAND_MARKER,
|
|
1765
|
+
legacyCommandMarkers: [CONTEXT_PROMOTION_LEGACY_HOOK_COMMAND_MARKER],
|
|
1766
|
+
defaultCommand: CONTEXT_PROMOTION_DEFAULT_HOOK_COMMAND,
|
|
1767
|
+
statusMessage: "Checking context promotion review"
|
|
1768
|
+
};
|
|
1769
|
+
var PC_CODEX_HOOK = {
|
|
1770
|
+
id: PC_HOOK_ID,
|
|
1771
|
+
commandMarker: PC_HOOK_COMMAND_MARKER,
|
|
1772
|
+
legacyCommandMarkers: [],
|
|
1773
|
+
defaultCommand: PC_DEFAULT_HOOK_COMMAND,
|
|
1774
|
+
statusMessage: "Checking pc handoff"
|
|
1775
|
+
};
|
|
1776
|
+
var isJsonRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1777
|
+
var readJsonRecord = (filePath) => {
|
|
1778
|
+
if (!existsSync2(filePath)) {
|
|
1779
|
+
return {};
|
|
1780
|
+
}
|
|
1781
|
+
const parsed = JSON.parse(readFileSync7(filePath, "utf-8"));
|
|
1782
|
+
if (!isJsonRecord(parsed)) {
|
|
1783
|
+
throw new Error("hooks.json must contain a JSON object");
|
|
1784
|
+
}
|
|
1785
|
+
return parsed;
|
|
1786
|
+
};
|
|
1787
|
+
var writeJsonRecord = (filePath, value) => {
|
|
1788
|
+
mkdirSync5(dirname7(filePath), { recursive: true });
|
|
1789
|
+
writeFileSync5(filePath, JSON.stringify(value, null, 2) + "\n", "utf-8");
|
|
1790
|
+
};
|
|
1791
|
+
var getOrCreateRecord = (record, key) => {
|
|
1792
|
+
const existing = record[key];
|
|
1793
|
+
if (isJsonRecord(existing)) {
|
|
1794
|
+
return existing;
|
|
1795
|
+
}
|
|
1796
|
+
const next = {};
|
|
1797
|
+
record[key] = next;
|
|
1798
|
+
return next;
|
|
1799
|
+
};
|
|
1800
|
+
var getArray = (record, key) => {
|
|
1801
|
+
const existing = record[key];
|
|
1802
|
+
return Array.isArray(existing) ? existing : [];
|
|
1803
|
+
};
|
|
1804
|
+
var handlerMatchesDefinition = (definition) => (handler) => isJsonRecord(handler) && typeof handler.command === "string" && [definition.commandMarker, ...definition.legacyCommandMarkers].some((marker) => handler.command.includes(marker));
|
|
1805
|
+
var handlerMatchesCommand = (handler, command) => isJsonRecord(handler) && handler.command === command;
|
|
1806
|
+
var groupHasDefinitionHook = (definition) => (group) => isJsonRecord(group) && getArray(group, "hooks").some(handlerMatchesDefinition(definition));
|
|
1807
|
+
var groupHasCurrentDefinitionHook = (group, command) => isJsonRecord(group) && getArray(group, "hooks").some((handler) => handlerMatchesCommand(handler, command));
|
|
1808
|
+
var countDefinitionHandlers = (groups, definition) => groups.reduce((count, group) => {
|
|
1809
|
+
if (!isJsonRecord(group)) {
|
|
1810
|
+
return count;
|
|
1811
|
+
}
|
|
1812
|
+
return count + getArray(group, "hooks").filter(handlerMatchesDefinition(definition)).length;
|
|
1813
|
+
}, 0);
|
|
1814
|
+
var configHasDefinitionHook = (config, definition) => {
|
|
1815
|
+
const hooks = config.hooks;
|
|
1816
|
+
if (!isJsonRecord(hooks)) {
|
|
1817
|
+
return false;
|
|
1818
|
+
}
|
|
1819
|
+
return getArray(hooks, POST_TOOL_USE_EVENT).some(groupHasDefinitionHook(definition));
|
|
1820
|
+
};
|
|
1821
|
+
var configHasOnlyCurrentDefinitionHook = (config, definition, command) => {
|
|
1822
|
+
const hooks = config.hooks;
|
|
1823
|
+
if (!isJsonRecord(hooks)) {
|
|
1824
|
+
return false;
|
|
1825
|
+
}
|
|
1826
|
+
const hasLegacy = getArray(hooks, PRE_TOOL_USE_EVENT).some(groupHasDefinitionHook(definition));
|
|
1827
|
+
const postGroups = getArray(hooks, POST_TOOL_USE_EVENT);
|
|
1828
|
+
const hasCurrent = postGroups.some((group) => groupHasCurrentDefinitionHook(group, command));
|
|
1829
|
+
return hasCurrent && !hasLegacy && countDefinitionHandlers(postGroups, definition) === 1;
|
|
1830
|
+
};
|
|
1831
|
+
var removeDefinitionHooksFromEvent = (hooks, eventName, definition) => {
|
|
1832
|
+
const previousGroups = getArray(hooks, eventName);
|
|
1833
|
+
let removed = false;
|
|
1834
|
+
const nextGroups = previousGroups.map((group) => {
|
|
1835
|
+
if (!isJsonRecord(group)) {
|
|
1836
|
+
return group;
|
|
1837
|
+
}
|
|
1838
|
+
const previousHandlers = getArray(group, "hooks");
|
|
1839
|
+
const nextHandlers = previousHandlers.filter((handler) => {
|
|
1840
|
+
const matches = handlerMatchesDefinition(definition)(handler);
|
|
1841
|
+
if (matches) {
|
|
1842
|
+
removed = true;
|
|
1843
|
+
}
|
|
1844
|
+
return !matches;
|
|
1845
|
+
});
|
|
1846
|
+
if (nextHandlers.length === 0) {
|
|
1847
|
+
return null;
|
|
1848
|
+
}
|
|
1849
|
+
return {
|
|
1850
|
+
...group,
|
|
1851
|
+
hooks: nextHandlers
|
|
1852
|
+
};
|
|
1853
|
+
}).filter((group) => group !== null);
|
|
1854
|
+
if (!removed) {
|
|
1855
|
+
return false;
|
|
1856
|
+
}
|
|
1857
|
+
if (nextGroups.length > 0) {
|
|
1858
|
+
hooks[eventName] = nextGroups;
|
|
1859
|
+
} else {
|
|
1860
|
+
delete hooks[eventName];
|
|
1861
|
+
}
|
|
1862
|
+
return true;
|
|
1863
|
+
};
|
|
1864
|
+
var resolveCodexHooksPath = (codexHomePath) => join9(codexHomePath, "hooks.json");
|
|
1865
|
+
var buildCodexHookCommand = (params) => {
|
|
1866
|
+
const command = params.overrideCommand?.trim() ?? params.definition.defaultCommand;
|
|
1867
|
+
if (!command.includes(params.definition.commandMarker)) {
|
|
1868
|
+
throw new Error(`${params.definition.id} hook command must include: ${params.definition.commandMarker}`);
|
|
1869
|
+
}
|
|
1870
|
+
return command;
|
|
1871
|
+
};
|
|
1872
|
+
var buildContextPromotionHookCommand = (overrideCommand) => buildCodexHookCommand({
|
|
1873
|
+
definition: CONTEXT_PROMOTION_CODEX_HOOK,
|
|
1874
|
+
overrideCommand
|
|
1875
|
+
});
|
|
1876
|
+
var inspectCodexHook = (params) => ({
|
|
1877
|
+
hooksPath: params.hooksPath,
|
|
1878
|
+
installed: configHasDefinitionHook(readJsonRecord(params.hooksPath), params.definition)
|
|
1879
|
+
});
|
|
1880
|
+
var inspectContextPromotionHook = (hooksPath) => ({
|
|
1881
|
+
hooksPath,
|
|
1882
|
+
installed: inspectCodexHook({ hooksPath, definition: CONTEXT_PROMOTION_CODEX_HOOK }).installed
|
|
1883
|
+
});
|
|
1884
|
+
var installCodexHook = (params) => {
|
|
1885
|
+
const config = readJsonRecord(params.hooksPath);
|
|
1886
|
+
if (configHasOnlyCurrentDefinitionHook(config, params.definition, params.command)) {
|
|
1887
|
+
return {
|
|
1888
|
+
hooksPath: params.hooksPath,
|
|
1889
|
+
installed: true,
|
|
1890
|
+
changed: false
|
|
1891
|
+
};
|
|
1892
|
+
}
|
|
1893
|
+
const hooks = getOrCreateRecord(config, "hooks");
|
|
1894
|
+
removeDefinitionHooksFromEvent(hooks, PRE_TOOL_USE_EVENT, params.definition);
|
|
1895
|
+
removeDefinitionHooksFromEvent(hooks, POST_TOOL_USE_EVENT, params.definition);
|
|
1896
|
+
const existingGroups = getArray(hooks, POST_TOOL_USE_EVENT);
|
|
1897
|
+
const nextGroup = {
|
|
1898
|
+
matcher: BASH_MATCHER,
|
|
1899
|
+
hooks: [
|
|
1900
|
+
{
|
|
1901
|
+
type: "command",
|
|
1902
|
+
command: params.command,
|
|
1903
|
+
timeout: 30,
|
|
1904
|
+
statusMessage: params.definition.statusMessage
|
|
1905
|
+
}
|
|
1906
|
+
]
|
|
1907
|
+
};
|
|
1908
|
+
hooks[POST_TOOL_USE_EVENT] = [...existingGroups, nextGroup];
|
|
1909
|
+
writeJsonRecord(params.hooksPath, config);
|
|
1910
|
+
return {
|
|
1911
|
+
hooksPath: params.hooksPath,
|
|
1912
|
+
installed: true,
|
|
1913
|
+
changed: true
|
|
1914
|
+
};
|
|
1915
|
+
};
|
|
1916
|
+
var installContextPromotionHook = (params) => installCodexHook({
|
|
1917
|
+
hooksPath: params.hooksPath,
|
|
1918
|
+
definition: CONTEXT_PROMOTION_CODEX_HOOK,
|
|
1919
|
+
command: params.command
|
|
1920
|
+
});
|
|
1921
|
+
var uninstallCodexHook = (params) => {
|
|
1922
|
+
const config = readJsonRecord(params.hooksPath);
|
|
1923
|
+
const hooks = config.hooks;
|
|
1924
|
+
if (!isJsonRecord(hooks)) {
|
|
1925
|
+
return { hooksPath: params.hooksPath, removed: false, changed: false };
|
|
1926
|
+
}
|
|
1927
|
+
const removedLegacy = removeDefinitionHooksFromEvent(hooks, PRE_TOOL_USE_EVENT, params.definition);
|
|
1928
|
+
const removedCurrent = removeDefinitionHooksFromEvent(hooks, POST_TOOL_USE_EVENT, params.definition);
|
|
1929
|
+
const removed = removedLegacy || removedCurrent;
|
|
1930
|
+
if (!removed) {
|
|
1931
|
+
return { hooksPath: params.hooksPath, removed: false, changed: false };
|
|
1932
|
+
}
|
|
1933
|
+
writeJsonRecord(params.hooksPath, config);
|
|
1934
|
+
return { hooksPath: params.hooksPath, removed: true, changed: true };
|
|
1935
|
+
};
|
|
1936
|
+
var uninstallContextPromotionHook = (hooksPath) => uninstallCodexHook({
|
|
1937
|
+
hooksPath,
|
|
1938
|
+
definition: CONTEXT_PROMOTION_CODEX_HOOK
|
|
1939
|
+
});
|
|
1940
|
+
|
|
1941
|
+
// src/core/studio-snapshot.ts
|
|
1942
|
+
var INTEGRATIONS_DATA_DIR = join10(COMPILER_DATA_DIR, "integrations");
|
|
1943
|
+
var SKILLS_DATA_DIR = join10(COMPILER_DATA_DIR, "skills");
|
|
1944
|
+
var SUBAGENTS_DATA_DIR = join10(COMPILER_DATA_DIR, "subagents");
|
|
1945
|
+
var DOCS_STATUS_RELATIVE_PATH = "docs/docs-status.md";
|
|
1946
|
+
var INTEGRATIONS_MANIFEST_FALLBACK_PATH = ".ai-ops/integrations-manifest.json";
|
|
1947
|
+
var SKILLS_MANIFEST_FALLBACK_PATH = ".ai-ops/skills-manifest.json";
|
|
1948
|
+
var SUBAGENTS_MANIFEST_FALLBACK_PATH = ".ai-ops/subagents-manifest.json";
|
|
1949
|
+
var HOOKS_FALLBACK_PATH = ".codex/hooks.json";
|
|
1950
|
+
var KNOWN_CODEX_HOOK_DEFINITIONS = [CONTEXT_PROMOTION_CODEX_HOOK, PC_CODEX_HOOK];
|
|
1951
|
+
var AUDIT_ISSUE_SOURCES_BY_CODE = {
|
|
1952
|
+
"missing-manifest": "manifest",
|
|
1953
|
+
"invalid-manifest": "manifest",
|
|
1954
|
+
"manifest-missing-managed-file": "manifest",
|
|
1955
|
+
"missing-context-index": "context-layer",
|
|
1956
|
+
"invalid-context-index": "context-layer",
|
|
1957
|
+
"context-missing-document": "context-layer",
|
|
1958
|
+
"context-document-mismatch": "context-layer",
|
|
1959
|
+
"context-extra-document": "context-layer",
|
|
1960
|
+
"missing-docs-status": "docs-status",
|
|
1961
|
+
"invalid-docs-status": "docs-status",
|
|
1962
|
+
"docs-status-missing-document": "docs-status",
|
|
1963
|
+
"docs-status-mismatch": "docs-status",
|
|
1964
|
+
"docs-status-extra-document": "docs-status",
|
|
1965
|
+
"missing-file": "file-system",
|
|
1966
|
+
"invalid-frontmatter": "frontmatter",
|
|
1967
|
+
"missing-managed-section": "managed-section",
|
|
1968
|
+
"source-hash-drift": "source-hash",
|
|
1969
|
+
"managed-source-hash-drift": "source-hash"
|
|
1970
|
+
};
|
|
1971
|
+
var AUDIT_ISSUE_ACTION_LABELS_BY_SOURCE = {
|
|
1972
|
+
manifest: "Review manifest record",
|
|
1973
|
+
"context-layer": "Review context index",
|
|
1974
|
+
"docs-status": "Review docs status",
|
|
1975
|
+
frontmatter: "Review frontmatter",
|
|
1976
|
+
"managed-section": "Review managed section",
|
|
1977
|
+
"file-system": "Review missing file",
|
|
1978
|
+
"source-hash": "Review source hash",
|
|
1979
|
+
unknown: null
|
|
1980
|
+
};
|
|
1981
|
+
var RecoverableContextDocumentSchema = z12.object({
|
|
1982
|
+
status: ProjectLayerDocumentStatusSchema,
|
|
1983
|
+
layer: z12.string().min(1),
|
|
1984
|
+
owner: z12.string().min(1),
|
|
1985
|
+
read_when: z12.array(z12.string().min(1)),
|
|
1986
|
+
update_when: z12.array(z12.string().min(1)),
|
|
1987
|
+
path: z12.string().min(1),
|
|
1988
|
+
contentHash: z12.string().min(1)
|
|
1989
|
+
});
|
|
1990
|
+
var RecoverableContextIndexSchema = z12.object({
|
|
1991
|
+
schemaVersion: z12.literal(1),
|
|
1992
|
+
kind: z12.literal("context-layer-index"),
|
|
1993
|
+
documents: z12.array(z12.unknown()),
|
|
1994
|
+
generatedAt: z12.string().min(1)
|
|
1995
|
+
});
|
|
1996
|
+
var getErrorMessage = (error) => error instanceof Error ? error.message : "unknown error";
|
|
1997
|
+
var resolveDefaultUserBasePath = () => process.env.AI_OPS_HOME ?? process.env.HOME ?? null;
|
|
1998
|
+
var resolveDefaultCodexHomePath = () => {
|
|
1999
|
+
if (process.env.CODEX_HOME && process.env.CODEX_HOME.length > 0) {
|
|
2000
|
+
return process.env.CODEX_HOME;
|
|
2001
|
+
}
|
|
2002
|
+
if (process.env.HOME && process.env.HOME.length > 0) {
|
|
2003
|
+
return join10(process.env.HOME, ".codex");
|
|
2004
|
+
}
|
|
2005
|
+
return null;
|
|
2006
|
+
};
|
|
2007
|
+
var buildSourceState = (params) => ({
|
|
2008
|
+
path: params.path,
|
|
2009
|
+
exists: params.exists,
|
|
2010
|
+
parsed: params.parsed,
|
|
2011
|
+
generatedAt: params.generatedAt ?? null,
|
|
2012
|
+
error: params.error ?? null
|
|
2013
|
+
});
|
|
2014
|
+
var createMissingSourceState = (path) => buildSourceState({ path, exists: false, parsed: false });
|
|
2015
|
+
var createUnavailableSourceState = (params) => buildSourceState({
|
|
2016
|
+
path: params.path,
|
|
2017
|
+
exists: false,
|
|
2018
|
+
parsed: false,
|
|
2019
|
+
error: params.reason
|
|
2020
|
+
});
|
|
2021
|
+
var hasErrors = (issues) => issues.some((issue2) => issue2.level === "error");
|
|
2022
|
+
var hasWarnings = (issues) => issues.some((issue2) => issue2.level === "warning");
|
|
2023
|
+
var getTrustWarning = (status) => {
|
|
2024
|
+
if (status === "Reserved") {
|
|
2025
|
+
return "Reserved document is not current decision-making evidence.";
|
|
2026
|
+
}
|
|
2027
|
+
if (status === "Draft") {
|
|
2028
|
+
return "Draft document requires review before use as decision-making evidence.";
|
|
2029
|
+
}
|
|
2030
|
+
if (status === "Archived") {
|
|
2031
|
+
return "Archived document is historical record and should not guide current operation.";
|
|
2032
|
+
}
|
|
2033
|
+
return null;
|
|
2034
|
+
};
|
|
2035
|
+
var uniqueStrings = (values) => [...new Set(values.filter((value) => value.length > 0))];
|
|
2036
|
+
var getManifestDocumentPaths = (manifest) => manifest === null ? [] : [
|
|
2037
|
+
...manifest.managed_files.map((file) => file.path),
|
|
2038
|
+
...manifest.project_files.map((file) => file.path),
|
|
2039
|
+
...manifest.packs.flatMap((pack) => pack.documents.map((file) => file.path)),
|
|
2040
|
+
...manifest.packs.flatMap((pack) => pack.files.map((file) => file.path))
|
|
2041
|
+
];
|
|
2042
|
+
var buildKnownAuditPaths = (params) => uniqueStrings([
|
|
2043
|
+
PROJECT_LAYER_MANIFEST_RELATIVE_PATH,
|
|
2044
|
+
PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH,
|
|
2045
|
+
DOCS_STATUS_RELATIVE_PATH,
|
|
2046
|
+
...getManifestDocumentPaths(params.manifest),
|
|
2047
|
+
...params.contextIndex?.documents.map((document) => document.path) ?? [],
|
|
2048
|
+
...params.documents.map((document) => document.path)
|
|
2049
|
+
]).sort((left, right) => right.length - left.length || left.localeCompare(right));
|
|
2050
|
+
var findKnownPathInMessage = (message, knownPaths) => knownPaths.find((path) => message.includes(path)) ?? null;
|
|
2051
|
+
var parsePathLikeToken = (value) => {
|
|
2052
|
+
const trimmed = value.trim().replace(/[.,;)]$/, "");
|
|
2053
|
+
if (trimmed.length === 0) {
|
|
2054
|
+
return null;
|
|
2055
|
+
}
|
|
2056
|
+
try {
|
|
2057
|
+
resolveProjectLayerFilePath("/", trimmed);
|
|
2058
|
+
return trimmed;
|
|
2059
|
+
} catch {
|
|
2060
|
+
return null;
|
|
2061
|
+
}
|
|
2062
|
+
};
|
|
2063
|
+
var extractTrailingIssuePath = (message) => {
|
|
2064
|
+
const trailingSegment = message.split(":").at(-1);
|
|
2065
|
+
if (trailingSegment === void 0) {
|
|
2066
|
+
return null;
|
|
2067
|
+
}
|
|
2068
|
+
const [firstToken] = trailingSegment.trim().split(/\s+/);
|
|
2069
|
+
return firstToken === void 0 ? null : parsePathLikeToken(firstToken);
|
|
2070
|
+
};
|
|
2071
|
+
var resolveIssueSource = (issue2) => AUDIT_ISSUE_SOURCES_BY_CODE[issue2.code] ?? "unknown";
|
|
2072
|
+
var resolveIssueAffectedPath = (params) => {
|
|
2073
|
+
if (params.issue.code === "missing-manifest" || params.issue.code === "invalid-manifest") {
|
|
2074
|
+
return PROJECT_LAYER_MANIFEST_RELATIVE_PATH;
|
|
2075
|
+
}
|
|
2076
|
+
if (params.issue.code === "missing-context-index" || params.issue.code === "invalid-context-index") {
|
|
2077
|
+
return PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH;
|
|
2078
|
+
}
|
|
2079
|
+
if (params.issue.code === "missing-docs-status" || params.issue.code === "invalid-docs-status") {
|
|
2080
|
+
return DOCS_STATUS_RELATIVE_PATH;
|
|
2081
|
+
}
|
|
2082
|
+
if (params.issue.code === "source-hash-drift") {
|
|
2083
|
+
return null;
|
|
2084
|
+
}
|
|
2085
|
+
const knownPath = findKnownPathInMessage(params.issue.message, params.knownPaths);
|
|
2086
|
+
if (knownPath !== null) {
|
|
2087
|
+
return knownPath;
|
|
2088
|
+
}
|
|
2089
|
+
if (params.source === "unknown") {
|
|
2090
|
+
return null;
|
|
2091
|
+
}
|
|
2092
|
+
return extractTrailingIssuePath(params.issue.message);
|
|
2093
|
+
};
|
|
2094
|
+
var normalizeStudioProjectIssue = (issue2, knownPaths = []) => {
|
|
2095
|
+
const source = resolveIssueSource(issue2);
|
|
2096
|
+
return {
|
|
2097
|
+
level: issue2.level,
|
|
2098
|
+
code: issue2.code,
|
|
2099
|
+
message: issue2.message,
|
|
2100
|
+
source,
|
|
2101
|
+
affectedPath: resolveIssueAffectedPath({ issue: issue2, source, knownPaths }),
|
|
2102
|
+
suggestedActionLabel: AUDIT_ISSUE_ACTION_LABELS_BY_SOURCE[source]
|
|
2103
|
+
};
|
|
2104
|
+
};
|
|
2105
|
+
var readProjectManifestSnapshot = (basePath) => {
|
|
2106
|
+
const manifestPath = resolveProjectLayerManifestPath(basePath);
|
|
2107
|
+
if (!existsSync3(manifestPath)) {
|
|
2108
|
+
return {
|
|
2109
|
+
source: createMissingSourceState(PROJECT_LAYER_MANIFEST_RELATIVE_PATH),
|
|
2110
|
+
manifest: null
|
|
2111
|
+
};
|
|
2112
|
+
}
|
|
2113
|
+
try {
|
|
2114
|
+
const manifest = readProjectLayerManifest(basePath);
|
|
2115
|
+
return {
|
|
2116
|
+
source: buildSourceState({
|
|
2117
|
+
path: PROJECT_LAYER_MANIFEST_RELATIVE_PATH,
|
|
2118
|
+
exists: true,
|
|
2119
|
+
parsed: manifest !== null,
|
|
2120
|
+
generatedAt: manifest?.generatedAt ?? null
|
|
2121
|
+
}),
|
|
2122
|
+
manifest
|
|
2123
|
+
};
|
|
2124
|
+
} catch (error) {
|
|
2125
|
+
return {
|
|
2126
|
+
source: buildSourceState({
|
|
2127
|
+
path: PROJECT_LAYER_MANIFEST_RELATIVE_PATH,
|
|
2128
|
+
exists: true,
|
|
2129
|
+
parsed: false,
|
|
2130
|
+
error: getErrorMessage(error)
|
|
2131
|
+
}),
|
|
2132
|
+
manifest: null
|
|
2133
|
+
};
|
|
2134
|
+
}
|
|
2135
|
+
};
|
|
2136
|
+
var readProjectContextIndexSnapshot = (basePath) => {
|
|
2137
|
+
const contextIndexPath = resolveProjectLayerContextIndexPath(basePath);
|
|
2138
|
+
if (!existsSync3(contextIndexPath)) {
|
|
2139
|
+
return {
|
|
2140
|
+
source: createMissingSourceState(PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH),
|
|
2141
|
+
contextIndex: null
|
|
2142
|
+
};
|
|
2143
|
+
}
|
|
2144
|
+
try {
|
|
2145
|
+
const parsedJson = JSON.parse(readFileSync8(contextIndexPath, "utf-8"));
|
|
2146
|
+
const strictContextIndex = ProjectLayerContextIndexSchema.safeParse(parsedJson);
|
|
2147
|
+
if (strictContextIndex.success) {
|
|
2148
|
+
return {
|
|
2149
|
+
source: buildSourceState({
|
|
2150
|
+
path: PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH,
|
|
2151
|
+
exists: true,
|
|
2152
|
+
parsed: true,
|
|
2153
|
+
generatedAt: strictContextIndex.data.generatedAt
|
|
2154
|
+
}),
|
|
2155
|
+
contextIndex: strictContextIndex.data
|
|
2156
|
+
};
|
|
2157
|
+
}
|
|
2158
|
+
const recoverableContextIndex = RecoverableContextIndexSchema.safeParse(parsedJson);
|
|
2159
|
+
if (!recoverableContextIndex.success) {
|
|
2160
|
+
return {
|
|
2161
|
+
source: buildSourceState({
|
|
2162
|
+
path: PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH,
|
|
2163
|
+
exists: true,
|
|
2164
|
+
parsed: false,
|
|
2165
|
+
error: strictContextIndex.error.message
|
|
2166
|
+
}),
|
|
2167
|
+
contextIndex: null
|
|
2168
|
+
};
|
|
2169
|
+
}
|
|
2170
|
+
const documents = recoverableContextIndex.data.documents.flatMap((document) => {
|
|
2171
|
+
const parsedDocument = RecoverableContextDocumentSchema.safeParse(document);
|
|
2172
|
+
return parsedDocument.success ? [parsedDocument.data] : [];
|
|
2173
|
+
});
|
|
2174
|
+
return {
|
|
2175
|
+
source: buildSourceState({
|
|
2176
|
+
path: PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH,
|
|
2177
|
+
exists: true,
|
|
2178
|
+
parsed: false,
|
|
2179
|
+
generatedAt: recoverableContextIndex.data.generatedAt,
|
|
2180
|
+
error: strictContextIndex.error.message
|
|
2181
|
+
}),
|
|
2182
|
+
contextIndex: {
|
|
2183
|
+
schemaVersion: 1,
|
|
2184
|
+
kind: "context-layer-index",
|
|
2185
|
+
documents,
|
|
2186
|
+
generatedAt: recoverableContextIndex.data.generatedAt
|
|
2187
|
+
}
|
|
2188
|
+
};
|
|
2189
|
+
} catch (error) {
|
|
2190
|
+
return {
|
|
2191
|
+
source: buildSourceState({
|
|
2192
|
+
path: PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH,
|
|
2193
|
+
exists: true,
|
|
2194
|
+
parsed: false,
|
|
2195
|
+
error: getErrorMessage(error)
|
|
2196
|
+
}),
|
|
2197
|
+
contextIndex: null
|
|
2198
|
+
};
|
|
2199
|
+
}
|
|
2200
|
+
};
|
|
2201
|
+
var readDocsStatusSourceState = (basePath) => {
|
|
2202
|
+
const docsStatusPath = resolveProjectLayerFilePath(basePath, DOCS_STATUS_RELATIVE_PATH);
|
|
2203
|
+
if (!existsSync3(docsStatusPath)) {
|
|
2204
|
+
return createMissingSourceState(DOCS_STATUS_RELATIVE_PATH);
|
|
2205
|
+
}
|
|
2206
|
+
try {
|
|
2207
|
+
parseProjectLayerDocument(DOCS_STATUS_RELATIVE_PATH, readFileSync8(docsStatusPath, "utf-8"));
|
|
2208
|
+
return buildSourceState({
|
|
2209
|
+
path: DOCS_STATUS_RELATIVE_PATH,
|
|
2210
|
+
exists: true,
|
|
2211
|
+
parsed: true
|
|
2212
|
+
});
|
|
2213
|
+
} catch (error) {
|
|
2214
|
+
return buildSourceState({
|
|
2215
|
+
path: DOCS_STATUS_RELATIVE_PATH,
|
|
2216
|
+
exists: true,
|
|
2217
|
+
parsed: false,
|
|
2218
|
+
error: getErrorMessage(error)
|
|
2219
|
+
});
|
|
2220
|
+
}
|
|
2221
|
+
};
|
|
2222
|
+
var buildDocumentProvenance = (manifest, path) => {
|
|
2223
|
+
if (manifest?.managed_files.some((file) => file.path === path) === true) {
|
|
2224
|
+
return "ai-ops-managed";
|
|
2225
|
+
}
|
|
2226
|
+
if (manifest?.project_files.some((file) => file.path === path) === true) {
|
|
2227
|
+
return "project-owned";
|
|
2228
|
+
}
|
|
2229
|
+
if (manifest?.packs.some((pack) => pack.documents.some((document) => document.path === path)) === true) {
|
|
2230
|
+
return "pack-document";
|
|
2231
|
+
}
|
|
2232
|
+
return "context-only";
|
|
2233
|
+
};
|
|
2234
|
+
var buildDocumentReadError = (code, message) => `${code}: ${message}`;
|
|
2235
|
+
var buildProjectDocumentSnapshot = (params) => {
|
|
2236
|
+
let absolutePath;
|
|
2237
|
+
try {
|
|
2238
|
+
absolutePath = resolveProjectLayerFilePath(params.basePath, params.indexed.path);
|
|
2239
|
+
} catch (error) {
|
|
2240
|
+
return {
|
|
2241
|
+
path: params.indexed.path,
|
|
2242
|
+
status: params.indexed.status,
|
|
2243
|
+
layer: params.indexed.layer,
|
|
2244
|
+
owner: params.indexed.owner,
|
|
2245
|
+
read_when: params.indexed.read_when,
|
|
2246
|
+
update_when: params.indexed.update_when,
|
|
2247
|
+
indexedContentHash: params.indexed.contentHash,
|
|
2248
|
+
currentContentHash: null,
|
|
2249
|
+
contentHashMatches: null,
|
|
2250
|
+
provenance: params.provenance,
|
|
2251
|
+
content: null,
|
|
2252
|
+
trustWarning: getTrustWarning(params.indexed.status),
|
|
2253
|
+
readError: buildDocumentReadError("unsafe-path", getErrorMessage(error))
|
|
2254
|
+
};
|
|
2255
|
+
}
|
|
2256
|
+
if (!existsSync3(absolutePath)) {
|
|
2257
|
+
return {
|
|
2258
|
+
path: params.indexed.path,
|
|
2259
|
+
status: params.indexed.status,
|
|
2260
|
+
layer: params.indexed.layer,
|
|
2261
|
+
owner: params.indexed.owner,
|
|
2262
|
+
read_when: params.indexed.read_when,
|
|
2263
|
+
update_when: params.indexed.update_when,
|
|
2264
|
+
indexedContentHash: params.indexed.contentHash,
|
|
2265
|
+
currentContentHash: null,
|
|
2266
|
+
contentHashMatches: null,
|
|
2267
|
+
provenance: params.provenance,
|
|
2268
|
+
content: null,
|
|
2269
|
+
trustWarning: getTrustWarning(params.indexed.status),
|
|
2270
|
+
readError: buildDocumentReadError("missing-file", `\uD30C\uC77C \uC5C6\uC74C: ${params.indexed.path}`)
|
|
2271
|
+
};
|
|
2272
|
+
}
|
|
2273
|
+
try {
|
|
2274
|
+
const document = parseProjectLayerDocument(params.indexed.path, readFileSync8(absolutePath, "utf-8"));
|
|
2275
|
+
return {
|
|
2276
|
+
path: params.indexed.path,
|
|
2277
|
+
status: params.indexed.status,
|
|
2278
|
+
layer: params.indexed.layer,
|
|
2279
|
+
owner: params.indexed.owner,
|
|
2280
|
+
read_when: params.indexed.read_when,
|
|
2281
|
+
update_when: params.indexed.update_when,
|
|
2282
|
+
indexedContentHash: params.indexed.contentHash,
|
|
2283
|
+
currentContentHash: document.contentHash,
|
|
2284
|
+
contentHashMatches: document.contentHash === params.indexed.contentHash,
|
|
2285
|
+
provenance: params.provenance,
|
|
2286
|
+
content: document.content,
|
|
2287
|
+
trustWarning: getTrustWarning(params.indexed.status),
|
|
2288
|
+
readError: null
|
|
2289
|
+
};
|
|
2290
|
+
} catch (error) {
|
|
2291
|
+
return {
|
|
2292
|
+
path: params.indexed.path,
|
|
2293
|
+
status: params.indexed.status,
|
|
2294
|
+
layer: params.indexed.layer,
|
|
2295
|
+
owner: params.indexed.owner,
|
|
2296
|
+
read_when: params.indexed.read_when,
|
|
2297
|
+
update_when: params.indexed.update_when,
|
|
2298
|
+
indexedContentHash: params.indexed.contentHash,
|
|
2299
|
+
currentContentHash: null,
|
|
2300
|
+
contentHashMatches: null,
|
|
2301
|
+
provenance: params.provenance,
|
|
2302
|
+
content: null,
|
|
2303
|
+
trustWarning: getTrustWarning(params.indexed.status),
|
|
2304
|
+
readError: buildDocumentReadError("invalid-frontmatter", getErrorMessage(error))
|
|
2305
|
+
};
|
|
2306
|
+
}
|
|
2307
|
+
};
|
|
2308
|
+
var resolveProjectState = (params) => {
|
|
2309
|
+
const isUninitialized = !params.manifest.source.exists && !params.contextIndex.source.exists;
|
|
2310
|
+
if (isUninitialized) {
|
|
2311
|
+
return "uninitialized";
|
|
2312
|
+
}
|
|
2313
|
+
const hasParseError = params.manifest.source.exists && !params.manifest.source.parsed || params.contextIndex.source.exists && !params.contextIndex.source.parsed || params.docsStatus.exists && !params.docsStatus.parsed;
|
|
2314
|
+
const hasDocumentReadError = params.documents.some((document) => document.readError !== null);
|
|
2315
|
+
if (hasParseError || params.hasAuditErrors || hasDocumentReadError) {
|
|
2316
|
+
return "degraded";
|
|
2317
|
+
}
|
|
2318
|
+
return "ready";
|
|
2319
|
+
};
|
|
2320
|
+
var buildProjectSnapshot = (basePath) => {
|
|
2321
|
+
const root = resolve6(basePath);
|
|
2322
|
+
const manifest = readProjectManifestSnapshot(root);
|
|
2323
|
+
const contextIndex = readProjectContextIndexSnapshot(root);
|
|
2324
|
+
const docsStatus = readDocsStatusSourceState(root);
|
|
2325
|
+
const auditReport = auditProjectLayer(root);
|
|
2326
|
+
const documents = contextIndex.contextIndex?.documents.map(
|
|
2327
|
+
(indexed) => buildProjectDocumentSnapshot({
|
|
2328
|
+
basePath: root,
|
|
2329
|
+
indexed,
|
|
2330
|
+
provenance: buildDocumentProvenance(manifest.manifest, indexed.path)
|
|
2331
|
+
})
|
|
2332
|
+
) ?? [];
|
|
2333
|
+
const auditHasErrors = hasErrors(auditReport.issues);
|
|
2334
|
+
const knownAuditPaths = buildKnownAuditPaths({
|
|
2335
|
+
manifest: manifest.manifest,
|
|
2336
|
+
contextIndex: contextIndex.contextIndex,
|
|
2337
|
+
documents
|
|
2338
|
+
});
|
|
2339
|
+
const auditIssues = auditReport.issues.map((issue2) => normalizeStudioProjectIssue(issue2, knownAuditPaths));
|
|
2340
|
+
return {
|
|
2341
|
+
root,
|
|
2342
|
+
state: resolveProjectState({
|
|
2343
|
+
manifest,
|
|
2344
|
+
contextIndex,
|
|
2345
|
+
docsStatus,
|
|
2346
|
+
documents,
|
|
2347
|
+
hasAuditErrors: auditHasErrors
|
|
2348
|
+
}),
|
|
2349
|
+
files: {
|
|
2350
|
+
manifest: manifest.source,
|
|
2351
|
+
contextIndex: contextIndex.source,
|
|
2352
|
+
docsStatus
|
|
2353
|
+
},
|
|
2354
|
+
audit: {
|
|
2355
|
+
currentSourceHash: auditReport.currentSourceHash,
|
|
2356
|
+
hasErrors: auditHasErrors,
|
|
2357
|
+
hasWarnings: hasWarnings(auditIssues),
|
|
2358
|
+
issues: auditIssues
|
|
2359
|
+
},
|
|
2360
|
+
documents
|
|
2361
|
+
};
|
|
2362
|
+
};
|
|
2363
|
+
var readRuntimeManifest = (params) => {
|
|
2364
|
+
if (params.manifestPath === null) {
|
|
2365
|
+
return {
|
|
2366
|
+
source: createUnavailableSourceState({
|
|
2367
|
+
path: params.fallbackPath,
|
|
2368
|
+
reason: params.unavailableReason ?? "Runtime home is unavailable."
|
|
2369
|
+
}),
|
|
2370
|
+
value: null
|
|
2371
|
+
};
|
|
2372
|
+
}
|
|
2373
|
+
if (!existsSync3(params.manifestPath)) {
|
|
2374
|
+
return {
|
|
2375
|
+
source: createMissingSourceState(params.manifestPath),
|
|
2376
|
+
value: null
|
|
2377
|
+
};
|
|
2378
|
+
}
|
|
2379
|
+
try {
|
|
2380
|
+
const value = params.read(params.manifestPath);
|
|
2381
|
+
return {
|
|
2382
|
+
source: buildSourceState({
|
|
2383
|
+
path: params.manifestPath,
|
|
2384
|
+
exists: true,
|
|
2385
|
+
parsed: value !== null,
|
|
2386
|
+
generatedAt: value === null ? null : params.getGeneratedAt(value)
|
|
2387
|
+
}),
|
|
2388
|
+
value
|
|
2389
|
+
};
|
|
2390
|
+
} catch (error) {
|
|
2391
|
+
return {
|
|
2392
|
+
source: buildSourceState({
|
|
2393
|
+
path: params.manifestPath,
|
|
2394
|
+
exists: true,
|
|
2395
|
+
parsed: false,
|
|
2396
|
+
error: getErrorMessage(error)
|
|
2397
|
+
}),
|
|
2398
|
+
value: null
|
|
2399
|
+
};
|
|
2400
|
+
}
|
|
2401
|
+
};
|
|
2402
|
+
var isJsonRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2403
|
+
var readHooksSourceState = (codexHomePath, unavailableReason) => {
|
|
2404
|
+
if (codexHomePath === null) {
|
|
2405
|
+
return createUnavailableSourceState({
|
|
2406
|
+
path: HOOKS_FALLBACK_PATH,
|
|
2407
|
+
reason: unavailableReason ?? "CODEX_HOME or HOME is required for Codex hooks."
|
|
2408
|
+
});
|
|
2409
|
+
}
|
|
2410
|
+
const hooksPath = resolveCodexHooksPath(codexHomePath);
|
|
2411
|
+
if (!existsSync3(hooksPath)) {
|
|
2412
|
+
return createMissingSourceState(hooksPath);
|
|
2413
|
+
}
|
|
2414
|
+
try {
|
|
2415
|
+
const parsed = JSON.parse(readFileSync8(hooksPath, "utf-8"));
|
|
2416
|
+
if (!isJsonRecord2(parsed)) {
|
|
2417
|
+
return buildSourceState({
|
|
2418
|
+
path: hooksPath,
|
|
2419
|
+
exists: true,
|
|
2420
|
+
parsed: false,
|
|
2421
|
+
error: "hooks.json must contain a JSON object"
|
|
2422
|
+
});
|
|
2423
|
+
}
|
|
2424
|
+
return buildSourceState({
|
|
2425
|
+
path: hooksPath,
|
|
2426
|
+
exists: true,
|
|
2427
|
+
parsed: true
|
|
2428
|
+
});
|
|
2429
|
+
} catch (error) {
|
|
2430
|
+
return buildSourceState({
|
|
2431
|
+
path: hooksPath,
|
|
2432
|
+
exists: true,
|
|
2433
|
+
parsed: false,
|
|
2434
|
+
error: getErrorMessage(error)
|
|
2435
|
+
});
|
|
2436
|
+
}
|
|
2437
|
+
};
|
|
2438
|
+
var getCatalogComponentId = (component) => component.id;
|
|
2439
|
+
var getInstalledComponentId = (component) => component.id;
|
|
2440
|
+
var findInstalledComponent = (integration, catalogComponent) => integration?.components.find(
|
|
2441
|
+
(component) => component.type === catalogComponent.type && getInstalledComponentId(component) === getCatalogComponentId(catalogComponent)
|
|
2442
|
+
) ?? null;
|
|
2443
|
+
var buildIntegrationComponentStatus = (params) => ({
|
|
2444
|
+
type: params.catalogComponent.type,
|
|
2445
|
+
id: getCatalogComponentId(params.catalogComponent),
|
|
2446
|
+
installed: params.installedComponent !== null,
|
|
2447
|
+
owned: params.installedComponent?.owned ?? null,
|
|
2448
|
+
catalog: params.catalogComponent,
|
|
2449
|
+
installedComponent: params.installedComponent
|
|
2450
|
+
});
|
|
2451
|
+
var buildIntegrationSnapshots = (installedIntegrations) => {
|
|
2452
|
+
const catalog = loadAllIntegrations(INTEGRATIONS_DATA_DIR);
|
|
2453
|
+
return catalog.map((entry) => {
|
|
2454
|
+
const installedIntegration = findInstalledIntegration(installedIntegrations, entry.id);
|
|
2455
|
+
return {
|
|
2456
|
+
id: entry.id,
|
|
2457
|
+
description: entry.description,
|
|
2458
|
+
installed: installedIntegration !== void 0,
|
|
2459
|
+
installedAt: installedIntegration?.installedAt ?? null,
|
|
2460
|
+
updatedAt: installedIntegration?.updatedAt ?? null,
|
|
2461
|
+
components: entry.components.map(
|
|
2462
|
+
(catalogComponent) => buildIntegrationComponentStatus({
|
|
2463
|
+
catalogComponent,
|
|
2464
|
+
installedComponent: findInstalledComponent(installedIntegration, catalogComponent)
|
|
2465
|
+
})
|
|
2466
|
+
)
|
|
2467
|
+
};
|
|
2468
|
+
});
|
|
2469
|
+
};
|
|
2470
|
+
var buildInstalledPathStates = (params) => {
|
|
2471
|
+
if (params.userBasePath === null) {
|
|
2472
|
+
return params.installedPaths.map((path) => ({ path, exists: false }));
|
|
2473
|
+
}
|
|
2474
|
+
return params.installedPaths.map((path) => ({
|
|
2475
|
+
path,
|
|
2476
|
+
exists: existsSync3(join10(params.userBasePath ?? "", path))
|
|
2477
|
+
}));
|
|
2478
|
+
};
|
|
2479
|
+
var buildInstalledSkillMap = (installedSkills) => new Map(
|
|
2480
|
+
installedSkills.map((skill) => [
|
|
2481
|
+
resolveCanonicalSkillId(skill.id),
|
|
2482
|
+
{
|
|
2483
|
+
...skill,
|
|
2484
|
+
id: resolveCanonicalSkillId(skill.id)
|
|
2485
|
+
}
|
|
2486
|
+
])
|
|
2487
|
+
);
|
|
2488
|
+
var buildSkillSnapshots = (params) => {
|
|
2489
|
+
const installed = buildInstalledSkillMap(params.installedSkills);
|
|
2490
|
+
return loadAllSkills(SKILLS_DATA_DIR).map((skill) => {
|
|
2491
|
+
const installedSkill = installed.get(skill.id);
|
|
2492
|
+
return {
|
|
2493
|
+
id: skill.id,
|
|
2494
|
+
kind: skill.kind,
|
|
2495
|
+
description: skill.description,
|
|
2496
|
+
supported_tools: skill.supported_tools,
|
|
2497
|
+
groups: skill.groups,
|
|
2498
|
+
installed: installedSkill !== void 0,
|
|
2499
|
+
installedTools: installedSkill?.tools ?? [],
|
|
2500
|
+
installedPaths: buildInstalledPathStates({
|
|
2501
|
+
userBasePath: params.userBasePath,
|
|
2502
|
+
installedPaths: installedSkill?.installed_paths ?? []
|
|
2503
|
+
}),
|
|
2504
|
+
sourceHash: installedSkill?.sourceHash ?? null
|
|
2505
|
+
};
|
|
2506
|
+
});
|
|
2507
|
+
};
|
|
2508
|
+
var buildInstalledSubagentMap = (installedSubagents) => new Map(installedSubagents.map((subagent) => [subagent.id, subagent]));
|
|
2509
|
+
var buildSubagentSnapshots = (params) => {
|
|
2510
|
+
const installed = buildInstalledSubagentMap(params.installedSubagents);
|
|
2511
|
+
return loadAllSubagents(SUBAGENTS_DATA_DIR).map((subagent) => {
|
|
2512
|
+
const installedSubagent = installed.get(subagent.id);
|
|
2513
|
+
return {
|
|
2514
|
+
id: subagent.id,
|
|
2515
|
+
description: subagent.frontmatter.codex.parsed.description,
|
|
2516
|
+
supported_tools: subagent.supported_tools,
|
|
2517
|
+
installed: installedSubagent !== void 0,
|
|
2518
|
+
installedTools: installedSubagent?.tools ?? [],
|
|
2519
|
+
installedPaths: buildInstalledPathStates({
|
|
2520
|
+
userBasePath: params.userBasePath,
|
|
2521
|
+
installedPaths: installedSubagent?.installed_paths ?? []
|
|
2522
|
+
}),
|
|
2523
|
+
sourceHash: installedSubagent?.sourceHash ?? null
|
|
2524
|
+
};
|
|
2525
|
+
});
|
|
2526
|
+
};
|
|
2527
|
+
var buildHookSnapshot = (params) => {
|
|
2528
|
+
if (params.codexHomePath === null) {
|
|
2529
|
+
return {
|
|
2530
|
+
id: params.definition.id,
|
|
2531
|
+
statusMessage: params.definition.statusMessage,
|
|
2532
|
+
hooksPath: null,
|
|
2533
|
+
installed: false,
|
|
2534
|
+
error: params.unavailableReason ?? "CODEX_HOME or HOME is required for Codex hooks."
|
|
2535
|
+
};
|
|
1588
2536
|
}
|
|
1589
|
-
const
|
|
1590
|
-
|
|
1591
|
-
|
|
2537
|
+
const hooksPath = resolveCodexHooksPath(params.codexHomePath);
|
|
2538
|
+
try {
|
|
2539
|
+
const status = inspectCodexHook({
|
|
2540
|
+
hooksPath,
|
|
2541
|
+
definition: params.definition
|
|
2542
|
+
});
|
|
2543
|
+
return {
|
|
2544
|
+
id: params.definition.id,
|
|
2545
|
+
statusMessage: params.definition.statusMessage,
|
|
2546
|
+
hooksPath: status.hooksPath,
|
|
2547
|
+
installed: status.installed,
|
|
2548
|
+
error: null
|
|
2549
|
+
};
|
|
2550
|
+
} catch (error) {
|
|
2551
|
+
return {
|
|
2552
|
+
id: params.definition.id,
|
|
2553
|
+
statusMessage: params.definition.statusMessage,
|
|
2554
|
+
hooksPath,
|
|
2555
|
+
installed: false,
|
|
2556
|
+
error: getErrorMessage(error)
|
|
2557
|
+
};
|
|
2558
|
+
}
|
|
2559
|
+
};
|
|
2560
|
+
var buildRuntimeSnapshot = (params) => {
|
|
2561
|
+
const userUnavailableReason = params.userBasePath === null ? "AI_OPS_HOME or HOME is required for user/global runtime manifests." : null;
|
|
2562
|
+
const codexUnavailableReason = params.codexHomePath === null ? "CODEX_HOME or HOME is required for Codex hooks." : null;
|
|
2563
|
+
const integrationManifest = readRuntimeManifest({
|
|
2564
|
+
manifestPath: params.userBasePath === null ? null : resolveIntegrationManifestPath(params.userBasePath),
|
|
2565
|
+
fallbackPath: INTEGRATIONS_MANIFEST_FALLBACK_PATH,
|
|
2566
|
+
unavailableReason: userUnavailableReason,
|
|
2567
|
+
read: readIntegrationManifest,
|
|
2568
|
+
getGeneratedAt: (manifest) => manifest.generatedAt
|
|
2569
|
+
});
|
|
2570
|
+
const skillRegistry = readRuntimeManifest({
|
|
2571
|
+
manifestPath: params.userBasePath === null ? null : resolveSkillRegistryPath(params.userBasePath),
|
|
2572
|
+
fallbackPath: SKILLS_MANIFEST_FALLBACK_PATH,
|
|
2573
|
+
unavailableReason: userUnavailableReason,
|
|
2574
|
+
read: readSkillRegistry,
|
|
2575
|
+
getGeneratedAt: (registry) => registry.generatedAt
|
|
2576
|
+
});
|
|
2577
|
+
const subagentManifest = readRuntimeManifest({
|
|
2578
|
+
manifestPath: params.userBasePath === null ? null : resolveSubagentManifestPath(params.userBasePath),
|
|
2579
|
+
fallbackPath: SUBAGENTS_MANIFEST_FALLBACK_PATH,
|
|
2580
|
+
unavailableReason: userUnavailableReason,
|
|
2581
|
+
read: readSubagentManifest,
|
|
2582
|
+
getGeneratedAt: (manifest) => manifest.generatedAt
|
|
2583
|
+
});
|
|
2584
|
+
const hooks = readHooksSourceState(params.codexHomePath, codexUnavailableReason);
|
|
2585
|
+
const installedIntegrations = integrationManifest.value?.integrations ?? [];
|
|
2586
|
+
const installedSkills = skillRegistry.value?.skills ?? [];
|
|
2587
|
+
const installedSubagents = subagentManifest.value?.subagents ?? [];
|
|
2588
|
+
return {
|
|
2589
|
+
available: params.userBasePath !== null,
|
|
2590
|
+
unavailableReason: userUnavailableReason,
|
|
2591
|
+
userBasePath: params.userBasePath,
|
|
2592
|
+
codexHomePath: params.codexHomePath,
|
|
2593
|
+
manifests: {
|
|
2594
|
+
integrations: integrationManifest.source,
|
|
2595
|
+
skills: skillRegistry.source,
|
|
2596
|
+
subagents: subagentManifest.source,
|
|
2597
|
+
hooks
|
|
2598
|
+
},
|
|
2599
|
+
integrations: buildIntegrationSnapshots(installedIntegrations),
|
|
2600
|
+
skills: buildSkillSnapshots({
|
|
2601
|
+
userBasePath: params.userBasePath,
|
|
2602
|
+
installedSkills
|
|
2603
|
+
}),
|
|
2604
|
+
subagents: buildSubagentSnapshots({
|
|
2605
|
+
userBasePath: params.userBasePath,
|
|
2606
|
+
installedSubagents
|
|
2607
|
+
}),
|
|
2608
|
+
hooks: KNOWN_CODEX_HOOK_DEFINITIONS.map(
|
|
2609
|
+
(definition) => buildHookSnapshot({
|
|
2610
|
+
codexHomePath: params.codexHomePath,
|
|
2611
|
+
definition,
|
|
2612
|
+
unavailableReason: codexUnavailableReason
|
|
2613
|
+
})
|
|
2614
|
+
)
|
|
2615
|
+
};
|
|
2616
|
+
};
|
|
2617
|
+
var buildStudioSnapshot = (params) => {
|
|
2618
|
+
const generatedAt = params.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
2619
|
+
const userBasePath = params.userBasePath === void 0 ? resolveDefaultUserBasePath() : params.userBasePath;
|
|
2620
|
+
const codexHomePath = params.codexHomePath === void 0 ? resolveDefaultCodexHomePath() : params.codexHomePath;
|
|
2621
|
+
return StudioSnapshotSchema.parse({
|
|
2622
|
+
schemaVersion: 1,
|
|
2623
|
+
kind: "ai-ops-studio-snapshot",
|
|
2624
|
+
generatedAt,
|
|
2625
|
+
cliVersion: params.cliVersion ?? getCliVersion(),
|
|
2626
|
+
project: buildProjectSnapshot(params.basePath),
|
|
2627
|
+
runtime: buildRuntimeSnapshot({
|
|
2628
|
+
userBasePath,
|
|
2629
|
+
codexHomePath
|
|
2630
|
+
})
|
|
2631
|
+
});
|
|
1592
2632
|
};
|
|
1593
2633
|
|
|
1594
2634
|
// src/core/pack.ts
|
|
1595
|
-
import { existsSync as
|
|
1596
|
-
import { dirname as
|
|
2635
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync6, readFileSync as readFileSync9, readdirSync as readdirSync4, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
2636
|
+
import { dirname as dirname8, isAbsolute as isAbsolute2, join as join11, relative as relative2, resolve as resolve7 } from "path";
|
|
1597
2637
|
var PACK_REGISTRY_FILENAME = "pack-registry.json";
|
|
1598
2638
|
var SPEC_LIFECYCLE_PACK_ID = "spec-lifecycle";
|
|
1599
2639
|
var PACK_INSTALL_ROOT = "docs/specs/";
|
|
@@ -1601,9 +2641,9 @@ var RESERVED_DOCUMENT_WARNINGS2 = [
|
|
|
1601
2641
|
"\uD310\uB2E8 \uADFC\uAC70\uB85C \uC0AC\uC6A9\uD558\uC9C0 \uB9C8\uC138\uC694",
|
|
1602
2642
|
"Do not use this document as current decision-making evidence"
|
|
1603
2643
|
];
|
|
1604
|
-
var DEFAULT_PACKS_DIR =
|
|
2644
|
+
var DEFAULT_PACKS_DIR = join11(COMPILER_DATA_DIR, "packs");
|
|
1605
2645
|
var includesReservedDocumentWarning2 = (content) => RESERVED_DOCUMENT_WARNINGS2.some((warning) => content.includes(warning));
|
|
1606
|
-
var readPackCatalog = (packsDir) => PackCatalogSchema.parse(JSON.parse(
|
|
2646
|
+
var readPackCatalog = (packsDir) => PackCatalogSchema.parse(JSON.parse(readFileSync9(join11(packsDir, PACK_REGISTRY_FILENAME), "utf-8")));
|
|
1607
2647
|
var assertPackInstallPath = (path) => {
|
|
1608
2648
|
if (!isSafeProjectLayerPath(path) || !path.startsWith(PACK_INSTALL_ROOT)) {
|
|
1609
2649
|
throw new Error(`Unsafe pack path: ${path}`);
|
|
@@ -1612,16 +2652,16 @@ var assertPackInstallPath = (path) => {
|
|
|
1612
2652
|
var readPackSourceFiles = (packDir) => {
|
|
1613
2653
|
const files = [];
|
|
1614
2654
|
const walk = (relativeDir = "") => {
|
|
1615
|
-
const absoluteDir = relativeDir.length > 0 ?
|
|
2655
|
+
const absoluteDir = relativeDir.length > 0 ? join11(packDir, relativeDir) : packDir;
|
|
1616
2656
|
const entries = readdirSync4(absoluteDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
1617
2657
|
for (const entry of entries) {
|
|
1618
|
-
const nextRelativePath = relativeDir.length > 0 ?
|
|
2658
|
+
const nextRelativePath = relativeDir.length > 0 ? join11(relativeDir, entry.name) : entry.name;
|
|
1619
2659
|
if (entry.isDirectory()) {
|
|
1620
2660
|
walk(nextRelativePath);
|
|
1621
2661
|
continue;
|
|
1622
2662
|
}
|
|
1623
2663
|
assertPackInstallPath(nextRelativePath);
|
|
1624
|
-
const content =
|
|
2664
|
+
const content = readFileSync9(join11(packDir, nextRelativePath), "utf-8");
|
|
1625
2665
|
files.push({
|
|
1626
2666
|
path: nextRelativePath,
|
|
1627
2667
|
content,
|
|
@@ -1656,8 +2696,8 @@ var loadAllPacks = (packsDir) => {
|
|
|
1656
2696
|
if (entry.id !== SPEC_LIFECYCLE_PACK_ID) {
|
|
1657
2697
|
throw new Error(`Unsupported pack id: ${entry.id}`);
|
|
1658
2698
|
}
|
|
1659
|
-
const packDir =
|
|
1660
|
-
const relativeFromPacks = relative2(
|
|
2699
|
+
const packDir = resolve7(packsDir, entry.source_path);
|
|
2700
|
+
const relativeFromPacks = relative2(resolve7(packsDir), packDir);
|
|
1661
2701
|
if (relativeFromPacks.length === 0 || relativeFromPacks.startsWith("..") || isAbsolute2(relativeFromPacks)) {
|
|
1662
2702
|
throw new Error(`Pack source path escapes packs dir: ${entry.source_path}`);
|
|
1663
2703
|
}
|
|
@@ -1679,11 +2719,11 @@ var resolvePackById = (packsDir, packId) => {
|
|
|
1679
2719
|
return pack;
|
|
1680
2720
|
};
|
|
1681
2721
|
var serializePackFileContent = (content) => content.length === 0 ? "" : content.trimEnd() + "\n";
|
|
1682
|
-
var readProjectFileHash = (basePath, relativePath) => computeHash([
|
|
2722
|
+
var readProjectFileHash = (basePath, relativePath) => computeHash([readFileSync9(resolveProjectLayerFilePath(basePath, relativePath), "utf-8").trimEnd()]);
|
|
1683
2723
|
var writePackFile = (basePath, file) => {
|
|
1684
2724
|
const absolutePath = resolveProjectLayerFilePath(basePath, file.path);
|
|
1685
|
-
|
|
1686
|
-
|
|
2725
|
+
mkdirSync6(dirname8(absolutePath), { recursive: true });
|
|
2726
|
+
writeFileSync6(absolutePath, serializePackFileContent(file.content), "utf-8");
|
|
1687
2727
|
};
|
|
1688
2728
|
var buildPackFileRecords = (files) => files.map((file) => ({
|
|
1689
2729
|
path: file.path,
|
|
@@ -1713,7 +2753,7 @@ var applyPackSourceFiles = (params) => {
|
|
|
1713
2753
|
for (const file of sourceFiles) {
|
|
1714
2754
|
const absolutePath = resolveProjectLayerFilePath(params.basePath, file.path);
|
|
1715
2755
|
const previous = previousByPath.get(file.path);
|
|
1716
|
-
if (!
|
|
2756
|
+
if (!existsSync4(absolutePath)) {
|
|
1717
2757
|
writePackFile(params.basePath, file);
|
|
1718
2758
|
written.push(file.path);
|
|
1719
2759
|
continue;
|
|
@@ -1737,7 +2777,7 @@ var applyPackSourceFiles = (params) => {
|
|
|
1737
2777
|
continue;
|
|
1738
2778
|
}
|
|
1739
2779
|
const absolutePath = resolveProjectLayerFilePath(params.basePath, previous.path);
|
|
1740
|
-
if (!
|
|
2780
|
+
if (!existsSync4(absolutePath)) {
|
|
1741
2781
|
notFound.push(previous.path);
|
|
1742
2782
|
continue;
|
|
1743
2783
|
}
|
|
@@ -1756,7 +2796,7 @@ var removePackFiles = (basePath, record) => {
|
|
|
1756
2796
|
const notFound = [];
|
|
1757
2797
|
for (const file of [...record.documents, ...record.files]) {
|
|
1758
2798
|
const absolutePath = resolveProjectLayerFilePath(basePath, file.path);
|
|
1759
|
-
if (!
|
|
2799
|
+
if (!existsSync4(absolutePath)) {
|
|
1760
2800
|
notFound.push(file.path);
|
|
1761
2801
|
continue;
|
|
1762
2802
|
}
|
|
@@ -1770,12 +2810,12 @@ var removePackFiles = (basePath, record) => {
|
|
|
1770
2810
|
return { written: [], refreshed: [], preserved, deleted, notFound };
|
|
1771
2811
|
};
|
|
1772
2812
|
var removeEmptyDirs2 = (basePath, relativePaths) => {
|
|
1773
|
-
const dirs = [...new Set(relativePaths.map((path) =>
|
|
2813
|
+
const dirs = [...new Set(relativePaths.map((path) => dirname8(path)).filter((dir) => dir !== "."))].sort(
|
|
1774
2814
|
(a, b) => b.length - a.length
|
|
1775
2815
|
);
|
|
1776
2816
|
for (const dir of dirs) {
|
|
1777
2817
|
const absoluteDir = resolveProjectLayerFilePath(basePath, dir);
|
|
1778
|
-
if (!
|
|
2818
|
+
if (!existsSync4(absoluteDir)) {
|
|
1779
2819
|
continue;
|
|
1780
2820
|
}
|
|
1781
2821
|
try {
|
|
@@ -1891,7 +2931,7 @@ var diffProjectLayerPack = (params) => {
|
|
|
1891
2931
|
}
|
|
1892
2932
|
for (const file of [...record.documents, ...record.files]) {
|
|
1893
2933
|
const absolutePath = resolveProjectLayerFilePath(params.basePath, file.path);
|
|
1894
|
-
if (!
|
|
2934
|
+
if (!existsSync4(absolutePath)) {
|
|
1895
2935
|
issues.push(packIssue("error", "missing-file", `\uD30C\uC77C \uC5C6\uC74C: ${file.path}`));
|
|
1896
2936
|
}
|
|
1897
2937
|
}
|
|
@@ -1902,21 +2942,21 @@ var diffProjectLayerPack = (params) => {
|
|
|
1902
2942
|
// src/core/context-promotion.ts
|
|
1903
2943
|
import { createHash as createHash2 } from "crypto";
|
|
1904
2944
|
import { execFileSync } from "child_process";
|
|
1905
|
-
import { existsSync as
|
|
1906
|
-
import { dirname as
|
|
1907
|
-
import { z as
|
|
2945
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync7, readFileSync as readFileSync10, statSync, writeFileSync as writeFileSync7 } from "fs";
|
|
2946
|
+
import { dirname as dirname9, join as join12, resolve as resolve8 } from "path";
|
|
2947
|
+
import { z as z14 } from "zod";
|
|
1908
2948
|
|
|
1909
2949
|
// src/core/tool-use-hook.ts
|
|
1910
|
-
import { z as
|
|
1911
|
-
var HookToolInputSchema =
|
|
1912
|
-
command:
|
|
2950
|
+
import { z as z13 } from "zod";
|
|
2951
|
+
var HookToolInputSchema = z13.object({
|
|
2952
|
+
command: z13.string().optional()
|
|
1913
2953
|
}).passthrough();
|
|
1914
|
-
var ToolUseHookInputSchema =
|
|
1915
|
-
hook_event_name:
|
|
1916
|
-
cwd:
|
|
1917
|
-
tool_name:
|
|
1918
|
-
tool_input:
|
|
1919
|
-
tool_response:
|
|
2954
|
+
var ToolUseHookInputSchema = z13.object({
|
|
2955
|
+
hook_event_name: z13.string(),
|
|
2956
|
+
cwd: z13.string(),
|
|
2957
|
+
tool_name: z13.string().optional(),
|
|
2958
|
+
tool_input: z13.unknown().optional(),
|
|
2959
|
+
tool_response: z13.unknown().optional()
|
|
1920
2960
|
}).passthrough();
|
|
1921
2961
|
var SHELL_CONTROL_TOKENS = /* @__PURE__ */ new Set(["&&", "||", ";", "|", "(", ")"]);
|
|
1922
2962
|
var SHELL_SCRIPT_FLAGS = /* @__PURE__ */ new Set(["-c", "-lc"]);
|
|
@@ -2047,7 +3087,7 @@ var isGitCommitCommand = (command) => {
|
|
|
2047
3087
|
(segment) => segmentInvokesGitCommit(segment) || segmentInvokesShellScriptWithGitCommit(segment)
|
|
2048
3088
|
);
|
|
2049
3089
|
};
|
|
2050
|
-
var
|
|
3090
|
+
var isJsonRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2051
3091
|
var numberField = (record, keys) => {
|
|
2052
3092
|
for (const key of keys) {
|
|
2053
3093
|
const value = record[key];
|
|
@@ -2091,7 +3131,7 @@ var toolResponseIndicatesFailure = (toolResponse) => {
|
|
|
2091
3131
|
if (typeof toolResponse === "string") {
|
|
2092
3132
|
return stringIndicatesGitCommitFailureOrSuccess(toolResponse) === true;
|
|
2093
3133
|
}
|
|
2094
|
-
if (!
|
|
3134
|
+
if (!isJsonRecord3(toolResponse)) {
|
|
2095
3135
|
return false;
|
|
2096
3136
|
}
|
|
2097
3137
|
const success = booleanField(toolResponse, ["success", "ok"]);
|
|
@@ -2133,35 +3173,35 @@ var CONTEXT_PROMOTION_SCOPE = {
|
|
|
2133
3173
|
PROJECT_LOCAL: "project-local",
|
|
2134
3174
|
GLOBAL: "global"
|
|
2135
3175
|
};
|
|
2136
|
-
var ContextPromotionDecisionSchema =
|
|
2137
|
-
|
|
2138
|
-
|
|
3176
|
+
var ContextPromotionDecisionSchema = z14.union([
|
|
3177
|
+
z14.literal(CONTEXT_PROMOTION_DECISION.PROMOTED),
|
|
3178
|
+
z14.literal(CONTEXT_PROMOTION_DECISION.NO_PROMOTION)
|
|
2139
3179
|
]);
|
|
2140
|
-
var ContextPromotionScopeSchema =
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
3180
|
+
var ContextPromotionScopeSchema = z14.union([
|
|
3181
|
+
z14.literal(CONTEXT_PROMOTION_SCOPE.CORE),
|
|
3182
|
+
z14.literal(CONTEXT_PROMOTION_SCOPE.PROJECT_LOCAL),
|
|
3183
|
+
z14.literal(CONTEXT_PROMOTION_SCOPE.GLOBAL)
|
|
2144
3184
|
]);
|
|
2145
|
-
var ContextPromotionReceiptSchema =
|
|
2146
|
-
fingerprint:
|
|
2147
|
-
commitHash:
|
|
3185
|
+
var ContextPromotionReceiptSchema = z14.object({
|
|
3186
|
+
fingerprint: z14.string().regex(/^[a-f0-9]{16}$/),
|
|
3187
|
+
commitHash: z14.string().regex(/^(NO_HEAD|[a-f0-9]{40})$/).optional(),
|
|
2148
3188
|
decision: ContextPromotionDecisionSchema,
|
|
2149
|
-
scopes:
|
|
2150
|
-
targets:
|
|
2151
|
-
summary:
|
|
2152
|
-
resolvedAt:
|
|
3189
|
+
scopes: z14.array(ContextPromotionScopeSchema),
|
|
3190
|
+
targets: z14.array(z14.string().min(1)),
|
|
3191
|
+
summary: z14.string().min(1),
|
|
3192
|
+
resolvedAt: z14.string().min(1)
|
|
2153
3193
|
}).strict();
|
|
2154
|
-
var ContextPromotionReceiptIndexSchema =
|
|
2155
|
-
schemaVersion:
|
|
2156
|
-
kind:
|
|
2157
|
-
projectKey:
|
|
2158
|
-
projectRoot:
|
|
2159
|
-
receipts:
|
|
3194
|
+
var ContextPromotionReceiptIndexSchema = z14.object({
|
|
3195
|
+
schemaVersion: z14.literal(1),
|
|
3196
|
+
kind: z14.literal("context-promotion-receipts"),
|
|
3197
|
+
projectKey: z14.string().regex(/^[a-f0-9]{12}$/),
|
|
3198
|
+
projectRoot: z14.string().min(1),
|
|
3199
|
+
receipts: z14.array(ContextPromotionReceiptSchema)
|
|
2160
3200
|
}).strict();
|
|
2161
3201
|
var RECEIPT_INDEX_FILENAME = "receipts-index.json";
|
|
2162
3202
|
var DEFAULT_PRUNE_MAX = 50;
|
|
2163
3203
|
var hashHex = (parts, length) => createHash2("sha256").update(parts.join("\0")).digest("hex").slice(0, length);
|
|
2164
|
-
var buildContextPromotionProjectKey = (gitRoot) => hashHex([
|
|
3204
|
+
var buildContextPromotionProjectKey = (gitRoot) => hashHex([resolve8(gitRoot)], 12);
|
|
2165
3205
|
var runGit = (cwd, args) => execFileSync("git", [...args], {
|
|
2166
3206
|
cwd,
|
|
2167
3207
|
encoding: "utf-8",
|
|
@@ -2186,13 +3226,13 @@ var readUntrackedFingerprintParts = (gitRoot) => {
|
|
|
2186
3226
|
const raw = runGit(gitRoot, ["ls-files", "--others", "--exclude-standard", "-z"]);
|
|
2187
3227
|
const paths = raw.split("\0").filter((path) => path.length > 0).sort((a, b) => a.localeCompare(b));
|
|
2188
3228
|
return paths.map((relativePath) => {
|
|
2189
|
-
const absolutePath =
|
|
3229
|
+
const absolutePath = join12(gitRoot, relativePath);
|
|
2190
3230
|
try {
|
|
2191
3231
|
const stat = statSync(absolutePath);
|
|
2192
3232
|
if (!stat.isFile()) {
|
|
2193
3233
|
return `${relativePath}:non-file`;
|
|
2194
3234
|
}
|
|
2195
|
-
const content =
|
|
3235
|
+
const content = readFileSync10(absolutePath);
|
|
2196
3236
|
return `${relativePath}:${createHash2("sha256").update(content).digest("hex")}`;
|
|
2197
3237
|
} catch {
|
|
2198
3238
|
throw new Error(`Unable to read untracked path for context promotion fingerprint: ${relativePath}`);
|
|
@@ -2206,15 +3246,15 @@ var readTrackedWorkingTreeFingerprintParts = (gitRoot) => {
|
|
|
2206
3246
|
return [
|
|
2207
3247
|
`raw:${rawDiff}`,
|
|
2208
3248
|
...paths.map((relativePath) => {
|
|
2209
|
-
const absolutePath =
|
|
2210
|
-
if (!
|
|
3249
|
+
const absolutePath = join12(gitRoot, relativePath);
|
|
3250
|
+
if (!existsSync5(absolutePath)) {
|
|
2211
3251
|
return `${relativePath}:deleted`;
|
|
2212
3252
|
}
|
|
2213
3253
|
const stat = statSync(absolutePath);
|
|
2214
3254
|
if (!stat.isFile()) {
|
|
2215
3255
|
return `${relativePath}:non-file`;
|
|
2216
3256
|
}
|
|
2217
|
-
const content =
|
|
3257
|
+
const content = readFileSync10(absolutePath);
|
|
2218
3258
|
return `${relativePath}:${createHash2("sha256").update(content).digest("hex")}`;
|
|
2219
3259
|
})
|
|
2220
3260
|
];
|
|
@@ -2232,19 +3272,19 @@ var computeContextPromotionFingerprint = (gitRoot) => hashHex(
|
|
|
2232
3272
|
],
|
|
2233
3273
|
16
|
|
2234
3274
|
);
|
|
2235
|
-
var resolveContextPromotionReceiptIndexPath = (params) =>
|
|
3275
|
+
var resolveContextPromotionReceiptIndexPath = (params) => join12(params.userBasePath, ".ai-ops", "context-promotion", "projects", params.projectKey, RECEIPT_INDEX_FILENAME);
|
|
2236
3276
|
var parseContextPromotionReceiptIndex = (json) => ContextPromotionReceiptIndexSchema.parse(JSON.parse(json));
|
|
2237
3277
|
var serializeContextPromotionReceiptIndex = (index) => JSON.stringify(index, null, 2) + "\n";
|
|
2238
3278
|
var readContextPromotionReceiptIndex = (indexPath) => {
|
|
2239
3279
|
try {
|
|
2240
|
-
return parseContextPromotionReceiptIndex(
|
|
3280
|
+
return parseContextPromotionReceiptIndex(readFileSync10(indexPath, "utf-8"));
|
|
2241
3281
|
} catch {
|
|
2242
3282
|
return null;
|
|
2243
3283
|
}
|
|
2244
3284
|
};
|
|
2245
3285
|
var writeContextPromotionReceiptIndex = (indexPath, index) => {
|
|
2246
|
-
|
|
2247
|
-
|
|
3286
|
+
mkdirSync7(dirname9(indexPath), { recursive: true });
|
|
3287
|
+
writeFileSync7(indexPath, serializeContextPromotionReceiptIndex(index), "utf-8");
|
|
2248
3288
|
};
|
|
2249
3289
|
var buildEmptyReceiptIndex = (params) => ({
|
|
2250
3290
|
schemaVersion: 1,
|
|
@@ -2292,9 +3332,9 @@ var pruneContextPromotionReceipts = (params) => {
|
|
|
2292
3332
|
writeContextPromotionReceiptIndex(params.indexPath, nextIndex);
|
|
2293
3333
|
return nextIndex;
|
|
2294
3334
|
};
|
|
2295
|
-
var hasContextPromotionLayer = (gitRoot) =>
|
|
3335
|
+
var hasContextPromotionLayer = (gitRoot) => existsSync5(join12(gitRoot, PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH));
|
|
2296
3336
|
var getContextPromotionStatus = (params) => {
|
|
2297
|
-
const cwd =
|
|
3337
|
+
const cwd = resolve8(params.cwd);
|
|
2298
3338
|
const gitRoot = resolveContextPromotionGitRoot(cwd);
|
|
2299
3339
|
if (!gitRoot) {
|
|
2300
3340
|
return {
|
|
@@ -2383,24 +3423,28 @@ var buildContextPromotionReviewPrompt = (status) => {
|
|
|
2383
3423
|
const projectRoot = status.gitRoot ?? status.cwd;
|
|
2384
3424
|
const cdCommand = `cd ${JSON.stringify(projectRoot)}`;
|
|
2385
3425
|
return [
|
|
2386
|
-
"Context Promotion Review should run for the completed work commit.",
|
|
3426
|
+
"Context Promotion Review should run for the completed work commit and review-loop learnings.",
|
|
2387
3427
|
"",
|
|
2388
3428
|
`Project root: ${projectRoot}`,
|
|
2389
3429
|
"This project root is authoritative for this review.",
|
|
2390
3430
|
"",
|
|
2391
|
-
"Use the `context-promotion-review` skill to review the just-created HEAD commit for reusable operating knowledge.",
|
|
3431
|
+
"Use the `context-promotion-review` skill to review the just-created HEAD commit plus current conversation/review-loop learnings for reusable operating knowledge.",
|
|
2392
3432
|
"",
|
|
2393
3433
|
"Scope boundary:",
|
|
2394
3434
|
`- Before inspecting files, anchor shell work in the project root above. If needed, run \`${cdCommand}\` first.`,
|
|
2395
3435
|
"- Do not inspect other repositories, parent directories, or earlier conversation workspaces.",
|
|
2396
3436
|
"- Do not search the web or external documentation for this review.",
|
|
2397
3437
|
"- If `AGENTS.md`, `docs/agent/*`, `docs/docs-status.md`, or other context-layer files are absent, report them as absent; do not substitute files from another repo.",
|
|
2398
|
-
"- Use only the just-created `HEAD` commit,
|
|
3438
|
+
"- Use only the just-created `HEAD` commit, current conversation/review-loop learnings, post-commit worktree state, and files under the project root.",
|
|
2399
3439
|
"",
|
|
2400
3440
|
"Review requirements:",
|
|
2401
3441
|
"- Do not amend, rewrite, or mix changes into the work commit.",
|
|
3442
|
+
"- Inspect the post-commit worktree state before deciding: run `git status --short`, `git diff --name-only`, `git diff --cached --name-only`, and `git ls-files --others --exclude-standard`.",
|
|
2402
3443
|
"- Inspect the completed commit before deciding: run `git show --stat HEAD`, `git show --name-only HEAD`, and `git show HEAD` when detail is needed.",
|
|
2403
3444
|
"- Cross-check existing `AGENTS.md`, `docs/agent/*`, `docs/docs-status.md`, and `.ai-ops/context-layer.json` first.",
|
|
3445
|
+
"- Treat `already-covered` as valid only when the Active context layer already has the same agent behavior rule; plans, tests, README, runbooks, and operator docs are evidence, not automatic coverage.",
|
|
3446
|
+
"- Check whether user corrections, repeated review findings, command routines, dirty worktree, untracked files, changeset pollution, or staging-scope hygiene produced a reusable `project-local` candidate.",
|
|
3447
|
+
"- Before `no-promotion`, briefly report near-miss or discarded candidates with reasons.",
|
|
2404
3448
|
"- Classify candidates as `core`, `project-local`, `global`, `already-covered`, or `no-promotion`.",
|
|
2405
3449
|
"- Ask the user before editing any file.",
|
|
2406
3450
|
"- If promotion is approved, edit only the approved context/global files, then stop for user inspection without committing.",
|
|
@@ -2456,9 +3500,9 @@ var evaluateContextPromotionPostToolUseHook = (params) => {
|
|
|
2456
3500
|
|
|
2457
3501
|
// src/core/pc-integration.ts
|
|
2458
3502
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
2459
|
-
import { existsSync as
|
|
2460
|
-
import { join as
|
|
2461
|
-
var normalizePath = (path) =>
|
|
3503
|
+
import { existsSync as existsSync6, readFileSync as readFileSync11, readdirSync as readdirSync5 } from "fs";
|
|
3504
|
+
import { join as join13, resolve as resolve9, sep } from "path";
|
|
3505
|
+
var normalizePath = (path) => resolve9(path.replace(/^~(?=$|\/)/, process.env.HOME ?? "~"));
|
|
2462
3506
|
var pathContains = (parentPath, childPath) => {
|
|
2463
3507
|
const parent = normalizePath(parentPath);
|
|
2464
3508
|
const child = normalizePath(childPath);
|
|
@@ -2495,7 +3539,7 @@ var parseListField = (content, labels) => {
|
|
|
2495
3539
|
};
|
|
2496
3540
|
var readTextFileOrNull = (filePath) => {
|
|
2497
3541
|
try {
|
|
2498
|
-
return
|
|
3542
|
+
return readFileSync11(filePath, "utf-8");
|
|
2499
3543
|
} catch {
|
|
2500
3544
|
return null;
|
|
2501
3545
|
}
|
|
@@ -2520,11 +3564,11 @@ var readGitHead2 = (cwd) => {
|
|
|
2520
3564
|
}
|
|
2521
3565
|
};
|
|
2522
3566
|
var listWorkspaceStatePaths = (contextRoot) => {
|
|
2523
|
-
const workspacesDir =
|
|
2524
|
-
if (!
|
|
3567
|
+
const workspacesDir = join13(contextRoot, "workspaces");
|
|
3568
|
+
if (!existsSync6(workspacesDir)) {
|
|
2525
3569
|
return [];
|
|
2526
3570
|
}
|
|
2527
|
-
return readdirSync5(workspacesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) =>
|
|
3571
|
+
return readdirSync5(workspacesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join13(workspacesDir, entry.name, "workspace-state.md")).filter((statePath) => existsSync6(statePath)).sort((a, b) => a.localeCompare(b));
|
|
2528
3572
|
};
|
|
2529
3573
|
var parseWorkspaceCandidate = (statePath) => {
|
|
2530
3574
|
const content = readTextFileOrNull(statePath);
|
|
@@ -2537,7 +3581,7 @@ var parseWorkspaceCandidate = (statePath) => {
|
|
|
2537
3581
|
}
|
|
2538
3582
|
const activeSection = extractSection(content, ["\uD65C\uC131 Workstream", "Active Workstream"]);
|
|
2539
3583
|
const activeWorkstreamId = parseListField(activeSection, ["ID", "Workstream ID", "Active Workstream"]);
|
|
2540
|
-
const workspaceDir =
|
|
3584
|
+
const workspaceDir = resolve9(statePath, "..");
|
|
2541
3585
|
const id = parseListField(content, ["\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 ID", "Workspace ID"]) ?? workspaceDir.split(sep).at(-1) ?? "unknown";
|
|
2542
3586
|
return {
|
|
2543
3587
|
id,
|
|
@@ -2567,11 +3611,11 @@ var parseRepoEntry = (entryPath) => {
|
|
|
2567
3611
|
};
|
|
2568
3612
|
};
|
|
2569
3613
|
var findCurrentEntry = (params) => {
|
|
2570
|
-
const reposDir =
|
|
2571
|
-
if (!
|
|
3614
|
+
const reposDir = join13(params.workspaceDir, "repos");
|
|
3615
|
+
if (!existsSync6(reposDir)) {
|
|
2572
3616
|
return null;
|
|
2573
3617
|
}
|
|
2574
|
-
const entries = readdirSync5(reposDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => parseRepoEntry(
|
|
3618
|
+
const entries = readdirSync5(reposDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => parseRepoEntry(join13(reposDir, entry.name))).filter((entry) => entry !== null).filter((entry) => {
|
|
2575
3619
|
const paths = [entry.path, entry.gitRoot].filter((path) => path !== null);
|
|
2576
3620
|
return paths.some((path) => pathContains(path, params.cwd));
|
|
2577
3621
|
}).sort((a, b) => {
|
|
@@ -2623,7 +3667,7 @@ var parseLastConfirmedCommitHash = (params) => {
|
|
|
2623
3667
|
var getPcHandoffStatus = (params) => {
|
|
2624
3668
|
const cwd = normalizePath(params.cwd);
|
|
2625
3669
|
const contextRoot = normalizePath(params.contextRoot);
|
|
2626
|
-
if (!
|
|
3670
|
+
if (!existsSync6(contextRoot)) {
|
|
2627
3671
|
return {
|
|
2628
3672
|
cwd,
|
|
2629
3673
|
contextRoot,
|
|
@@ -2666,7 +3710,7 @@ var getPcHandoffStatus = (params) => {
|
|
|
2666
3710
|
skipReason: "active pc workstream not selected"
|
|
2667
3711
|
};
|
|
2668
3712
|
}
|
|
2669
|
-
const activeWorkstreamPath =
|
|
3713
|
+
const activeWorkstreamPath = join13(workspace.workspaceDir, "workstreams", `${workspace.activeWorkstreamId}.md`);
|
|
2670
3714
|
const activeWorkstreamContent = readTextFileOrNull(activeWorkstreamPath);
|
|
2671
3715
|
if (!activeWorkstreamContent) {
|
|
2672
3716
|
return {
|
|
@@ -2783,204 +3827,12 @@ var evaluatePcPostToolUseHook = (params) => {
|
|
|
2783
3827
|
return buildPostToolUseOutput2(buildPcDonePrompt({ status, head, gitRoot }));
|
|
2784
3828
|
};
|
|
2785
3829
|
|
|
2786
|
-
// src/core/codex-hook.ts
|
|
2787
|
-
import { existsSync as existsSync5, mkdirSync as mkdirSync7, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "fs";
|
|
2788
|
-
import { dirname as dirname9, join as join12 } from "path";
|
|
2789
|
-
var CONTEXT_PROMOTION_HOOK_ID = "context-promotion";
|
|
2790
|
-
var CONTEXT_PROMOTION_HOOK_COMMAND_MARKER = "context-promotion hook post-tool-use";
|
|
2791
|
-
var CONTEXT_PROMOTION_LEGACY_HOOK_COMMAND_MARKER = "context-promotion hook pre-tool-use";
|
|
2792
|
-
var CONTEXT_PROMOTION_DEFAULT_HOOK_COMMAND = `ai-ops ${CONTEXT_PROMOTION_HOOK_COMMAND_MARKER}`;
|
|
2793
|
-
var PC_HOOK_ID = "pc";
|
|
2794
|
-
var PC_HOOK_COMMAND_MARKER = "integration hook post-tool-use pc";
|
|
2795
|
-
var PC_DEFAULT_HOOK_COMMAND = `ai-ops ${PC_HOOK_COMMAND_MARKER}`;
|
|
2796
|
-
var PRE_TOOL_USE_EVENT = "PreToolUse";
|
|
2797
|
-
var POST_TOOL_USE_EVENT = "PostToolUse";
|
|
2798
|
-
var BASH_MATCHER = "^Bash$";
|
|
2799
|
-
var CONTEXT_PROMOTION_CODEX_HOOK = {
|
|
2800
|
-
id: CONTEXT_PROMOTION_HOOK_ID,
|
|
2801
|
-
commandMarker: CONTEXT_PROMOTION_HOOK_COMMAND_MARKER,
|
|
2802
|
-
legacyCommandMarkers: [CONTEXT_PROMOTION_LEGACY_HOOK_COMMAND_MARKER],
|
|
2803
|
-
defaultCommand: CONTEXT_PROMOTION_DEFAULT_HOOK_COMMAND,
|
|
2804
|
-
statusMessage: "Checking context promotion review"
|
|
2805
|
-
};
|
|
2806
|
-
var PC_CODEX_HOOK = {
|
|
2807
|
-
id: PC_HOOK_ID,
|
|
2808
|
-
commandMarker: PC_HOOK_COMMAND_MARKER,
|
|
2809
|
-
legacyCommandMarkers: [],
|
|
2810
|
-
defaultCommand: PC_DEFAULT_HOOK_COMMAND,
|
|
2811
|
-
statusMessage: "Checking pc handoff"
|
|
2812
|
-
};
|
|
2813
|
-
var isJsonRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2814
|
-
var readJsonRecord = (filePath) => {
|
|
2815
|
-
if (!existsSync5(filePath)) {
|
|
2816
|
-
return {};
|
|
2817
|
-
}
|
|
2818
|
-
const parsed = JSON.parse(readFileSync10(filePath, "utf-8"));
|
|
2819
|
-
if (!isJsonRecord2(parsed)) {
|
|
2820
|
-
throw new Error("hooks.json must contain a JSON object");
|
|
2821
|
-
}
|
|
2822
|
-
return parsed;
|
|
2823
|
-
};
|
|
2824
|
-
var writeJsonRecord = (filePath, value) => {
|
|
2825
|
-
mkdirSync7(dirname9(filePath), { recursive: true });
|
|
2826
|
-
writeFileSync7(filePath, JSON.stringify(value, null, 2) + "\n", "utf-8");
|
|
2827
|
-
};
|
|
2828
|
-
var getOrCreateRecord = (record, key) => {
|
|
2829
|
-
const existing = record[key];
|
|
2830
|
-
if (isJsonRecord2(existing)) {
|
|
2831
|
-
return existing;
|
|
2832
|
-
}
|
|
2833
|
-
const next = {};
|
|
2834
|
-
record[key] = next;
|
|
2835
|
-
return next;
|
|
2836
|
-
};
|
|
2837
|
-
var getArray = (record, key) => {
|
|
2838
|
-
const existing = record[key];
|
|
2839
|
-
return Array.isArray(existing) ? existing : [];
|
|
2840
|
-
};
|
|
2841
|
-
var handlerMatchesDefinition = (definition) => (handler) => isJsonRecord2(handler) && typeof handler.command === "string" && [definition.commandMarker, ...definition.legacyCommandMarkers].some((marker) => handler.command.includes(marker));
|
|
2842
|
-
var handlerMatchesCommand = (handler, command) => isJsonRecord2(handler) && handler.command === command;
|
|
2843
|
-
var groupHasDefinitionHook = (definition) => (group) => isJsonRecord2(group) && getArray(group, "hooks").some(handlerMatchesDefinition(definition));
|
|
2844
|
-
var groupHasCurrentDefinitionHook = (group, command) => isJsonRecord2(group) && getArray(group, "hooks").some((handler) => handlerMatchesCommand(handler, command));
|
|
2845
|
-
var countDefinitionHandlers = (groups, definition) => groups.reduce((count, group) => {
|
|
2846
|
-
if (!isJsonRecord2(group)) {
|
|
2847
|
-
return count;
|
|
2848
|
-
}
|
|
2849
|
-
return count + getArray(group, "hooks").filter(handlerMatchesDefinition(definition)).length;
|
|
2850
|
-
}, 0);
|
|
2851
|
-
var configHasDefinitionHook = (config, definition) => {
|
|
2852
|
-
const hooks = config.hooks;
|
|
2853
|
-
if (!isJsonRecord2(hooks)) {
|
|
2854
|
-
return false;
|
|
2855
|
-
}
|
|
2856
|
-
return getArray(hooks, POST_TOOL_USE_EVENT).some(groupHasDefinitionHook(definition));
|
|
2857
|
-
};
|
|
2858
|
-
var configHasOnlyCurrentDefinitionHook = (config, definition, command) => {
|
|
2859
|
-
const hooks = config.hooks;
|
|
2860
|
-
if (!isJsonRecord2(hooks)) {
|
|
2861
|
-
return false;
|
|
2862
|
-
}
|
|
2863
|
-
const hasLegacy = getArray(hooks, PRE_TOOL_USE_EVENT).some(groupHasDefinitionHook(definition));
|
|
2864
|
-
const postGroups = getArray(hooks, POST_TOOL_USE_EVENT);
|
|
2865
|
-
const hasCurrent = postGroups.some((group) => groupHasCurrentDefinitionHook(group, command));
|
|
2866
|
-
return hasCurrent && !hasLegacy && countDefinitionHandlers(postGroups, definition) === 1;
|
|
2867
|
-
};
|
|
2868
|
-
var removeDefinitionHooksFromEvent = (hooks, eventName, definition) => {
|
|
2869
|
-
const previousGroups = getArray(hooks, eventName);
|
|
2870
|
-
let removed = false;
|
|
2871
|
-
const nextGroups = previousGroups.map((group) => {
|
|
2872
|
-
if (!isJsonRecord2(group)) {
|
|
2873
|
-
return group;
|
|
2874
|
-
}
|
|
2875
|
-
const previousHandlers = getArray(group, "hooks");
|
|
2876
|
-
const nextHandlers = previousHandlers.filter((handler) => {
|
|
2877
|
-
const matches = handlerMatchesDefinition(definition)(handler);
|
|
2878
|
-
if (matches) {
|
|
2879
|
-
removed = true;
|
|
2880
|
-
}
|
|
2881
|
-
return !matches;
|
|
2882
|
-
});
|
|
2883
|
-
if (nextHandlers.length === 0) {
|
|
2884
|
-
return null;
|
|
2885
|
-
}
|
|
2886
|
-
return {
|
|
2887
|
-
...group,
|
|
2888
|
-
hooks: nextHandlers
|
|
2889
|
-
};
|
|
2890
|
-
}).filter((group) => group !== null);
|
|
2891
|
-
if (!removed) {
|
|
2892
|
-
return false;
|
|
2893
|
-
}
|
|
2894
|
-
if (nextGroups.length > 0) {
|
|
2895
|
-
hooks[eventName] = nextGroups;
|
|
2896
|
-
} else {
|
|
2897
|
-
delete hooks[eventName];
|
|
2898
|
-
}
|
|
2899
|
-
return true;
|
|
2900
|
-
};
|
|
2901
|
-
var resolveCodexHooksPath = (codexHomePath) => join12(codexHomePath, "hooks.json");
|
|
2902
|
-
var buildCodexHookCommand = (params) => {
|
|
2903
|
-
const command = params.overrideCommand?.trim() ?? params.definition.defaultCommand;
|
|
2904
|
-
if (!command.includes(params.definition.commandMarker)) {
|
|
2905
|
-
throw new Error(`${params.definition.id} hook command must include: ${params.definition.commandMarker}`);
|
|
2906
|
-
}
|
|
2907
|
-
return command;
|
|
2908
|
-
};
|
|
2909
|
-
var buildContextPromotionHookCommand = (overrideCommand) => buildCodexHookCommand({
|
|
2910
|
-
definition: CONTEXT_PROMOTION_CODEX_HOOK,
|
|
2911
|
-
overrideCommand
|
|
2912
|
-
});
|
|
2913
|
-
var inspectCodexHook = (params) => ({
|
|
2914
|
-
hooksPath: params.hooksPath,
|
|
2915
|
-
installed: configHasDefinitionHook(readJsonRecord(params.hooksPath), params.definition)
|
|
2916
|
-
});
|
|
2917
|
-
var inspectContextPromotionHook = (hooksPath) => ({
|
|
2918
|
-
hooksPath,
|
|
2919
|
-
installed: inspectCodexHook({ hooksPath, definition: CONTEXT_PROMOTION_CODEX_HOOK }).installed
|
|
2920
|
-
});
|
|
2921
|
-
var installCodexHook = (params) => {
|
|
2922
|
-
const config = readJsonRecord(params.hooksPath);
|
|
2923
|
-
if (configHasOnlyCurrentDefinitionHook(config, params.definition, params.command)) {
|
|
2924
|
-
return {
|
|
2925
|
-
hooksPath: params.hooksPath,
|
|
2926
|
-
installed: true,
|
|
2927
|
-
changed: false
|
|
2928
|
-
};
|
|
2929
|
-
}
|
|
2930
|
-
const hooks = getOrCreateRecord(config, "hooks");
|
|
2931
|
-
removeDefinitionHooksFromEvent(hooks, PRE_TOOL_USE_EVENT, params.definition);
|
|
2932
|
-
removeDefinitionHooksFromEvent(hooks, POST_TOOL_USE_EVENT, params.definition);
|
|
2933
|
-
const existingGroups = getArray(hooks, POST_TOOL_USE_EVENT);
|
|
2934
|
-
const nextGroup = {
|
|
2935
|
-
matcher: BASH_MATCHER,
|
|
2936
|
-
hooks: [
|
|
2937
|
-
{
|
|
2938
|
-
type: "command",
|
|
2939
|
-
command: params.command,
|
|
2940
|
-
timeout: 30,
|
|
2941
|
-
statusMessage: params.definition.statusMessage
|
|
2942
|
-
}
|
|
2943
|
-
]
|
|
2944
|
-
};
|
|
2945
|
-
hooks[POST_TOOL_USE_EVENT] = [...existingGroups, nextGroup];
|
|
2946
|
-
writeJsonRecord(params.hooksPath, config);
|
|
2947
|
-
return {
|
|
2948
|
-
hooksPath: params.hooksPath,
|
|
2949
|
-
installed: true,
|
|
2950
|
-
changed: true
|
|
2951
|
-
};
|
|
2952
|
-
};
|
|
2953
|
-
var installContextPromotionHook = (params) => installCodexHook({
|
|
2954
|
-
hooksPath: params.hooksPath,
|
|
2955
|
-
definition: CONTEXT_PROMOTION_CODEX_HOOK,
|
|
2956
|
-
command: params.command
|
|
2957
|
-
});
|
|
2958
|
-
var uninstallCodexHook = (params) => {
|
|
2959
|
-
const config = readJsonRecord(params.hooksPath);
|
|
2960
|
-
const hooks = config.hooks;
|
|
2961
|
-
if (!isJsonRecord2(hooks)) {
|
|
2962
|
-
return { hooksPath: params.hooksPath, removed: false, changed: false };
|
|
2963
|
-
}
|
|
2964
|
-
const removedLegacy = removeDefinitionHooksFromEvent(hooks, PRE_TOOL_USE_EVENT, params.definition);
|
|
2965
|
-
const removedCurrent = removeDefinitionHooksFromEvent(hooks, POST_TOOL_USE_EVENT, params.definition);
|
|
2966
|
-
const removed = removedLegacy || removedCurrent;
|
|
2967
|
-
if (!removed) {
|
|
2968
|
-
return { hooksPath: params.hooksPath, removed: false, changed: false };
|
|
2969
|
-
}
|
|
2970
|
-
writeJsonRecord(params.hooksPath, config);
|
|
2971
|
-
return { hooksPath: params.hooksPath, removed: true, changed: true };
|
|
2972
|
-
};
|
|
2973
|
-
var uninstallContextPromotionHook = (hooksPath) => uninstallCodexHook({
|
|
2974
|
-
hooksPath,
|
|
2975
|
-
definition: CONTEXT_PROMOTION_CODEX_HOOK
|
|
2976
|
-
});
|
|
2977
|
-
|
|
2978
3830
|
// src/lib/paths.ts
|
|
2979
|
-
import { join as
|
|
2980
|
-
var resolveSkillsDir = () =>
|
|
2981
|
-
var resolveSubagentsDir = () =>
|
|
2982
|
-
var resolvePacksDir = () =>
|
|
2983
|
-
var resolveIntegrationsDir = () =>
|
|
3831
|
+
import { join as join14 } from "path";
|
|
3832
|
+
var resolveSkillsDir = () => join14(COMPILER_DATA_DIR, "skills");
|
|
3833
|
+
var resolveSubagentsDir = () => join14(COMPILER_DATA_DIR, "subagents");
|
|
3834
|
+
var resolvePacksDir = () => join14(COMPILER_DATA_DIR, "packs");
|
|
3835
|
+
var resolveIntegrationsDir = () => join14(COMPILER_DATA_DIR, "integrations");
|
|
2984
3836
|
var resolveBasePath = () => process.cwd();
|
|
2985
3837
|
var resolveUserBasePath = () => {
|
|
2986
3838
|
const userBasePath = process.env.AI_OPS_HOME ?? process.env.HOME;
|
|
@@ -3228,6 +4080,43 @@ ${result.notFound.map((file) => ` ${file}`).join("\n")}`);
|
|
|
3228
4080
|
p6.outro("ai-ops uninstall \uC644\uB8CC");
|
|
3229
4081
|
};
|
|
3230
4082
|
|
|
4083
|
+
// src/commands/studio.ts
|
|
4084
|
+
import { join as join15 } from "path";
|
|
4085
|
+
var resolveOptionalUserBasePath = () => process.env.AI_OPS_HOME ?? process.env.HOME ?? null;
|
|
4086
|
+
var resolveOptionalCodexHomePath = () => {
|
|
4087
|
+
if (process.env.CODEX_HOME && process.env.CODEX_HOME.length > 0) {
|
|
4088
|
+
return process.env.CODEX_HOME;
|
|
4089
|
+
}
|
|
4090
|
+
if (process.env.HOME && process.env.HOME.length > 0) {
|
|
4091
|
+
return join15(process.env.HOME, ".codex");
|
|
4092
|
+
}
|
|
4093
|
+
return null;
|
|
4094
|
+
};
|
|
4095
|
+
var reportStudioSnapshotError = (error) => {
|
|
4096
|
+
const message = error instanceof Error ? error.message : "unknown error";
|
|
4097
|
+
process.stderr.write(`[studio-snapshot] ${message}
|
|
4098
|
+
`);
|
|
4099
|
+
process.exitCode = 1;
|
|
4100
|
+
};
|
|
4101
|
+
var studioSnapshotCommand = async (opts) => {
|
|
4102
|
+
if (opts.json !== true) {
|
|
4103
|
+
process.stderr.write("[studio-snapshot] --json is required\n");
|
|
4104
|
+
process.exitCode = 1;
|
|
4105
|
+
return;
|
|
4106
|
+
}
|
|
4107
|
+
try {
|
|
4108
|
+
const snapshot = buildStudioSnapshot({
|
|
4109
|
+
basePath: resolveBasePath(),
|
|
4110
|
+
userBasePath: resolveOptionalUserBasePath(),
|
|
4111
|
+
codexHomePath: resolveOptionalCodexHomePath()
|
|
4112
|
+
});
|
|
4113
|
+
process.stdout.write(`${JSON.stringify(snapshot, null, 2)}
|
|
4114
|
+
`);
|
|
4115
|
+
} catch (error) {
|
|
4116
|
+
reportStudioSnapshotError(error);
|
|
4117
|
+
}
|
|
4118
|
+
};
|
|
4119
|
+
|
|
3231
4120
|
// src/commands/skill.ts
|
|
3232
4121
|
import * as p7 from "@clack/prompts";
|
|
3233
4122
|
import { rmSync as rmSync5 } from "fs";
|
|
@@ -3264,17 +4153,17 @@ var findInstalledSkill = (installedSkills, skillId) => {
|
|
|
3264
4153
|
};
|
|
3265
4154
|
|
|
3266
4155
|
// src/lib/skill-install.ts
|
|
3267
|
-
import { existsSync as
|
|
3268
|
-
import { dirname as dirname10, resolve as
|
|
4156
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync8, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "fs";
|
|
4157
|
+
import { dirname as dirname10, resolve as resolve10 } from "path";
|
|
3269
4158
|
var installSkillPackages = (basePath, packages) => {
|
|
3270
4159
|
const writtenRoots = [];
|
|
3271
4160
|
for (const skillPackage of packages) {
|
|
3272
|
-
const absRoot =
|
|
3273
|
-
if (
|
|
4161
|
+
const absRoot = resolve10(basePath, skillPackage.rootDir);
|
|
4162
|
+
if (existsSync7(absRoot)) {
|
|
3274
4163
|
rmSync4(absRoot, { recursive: true, force: true });
|
|
3275
4164
|
}
|
|
3276
4165
|
for (const file of skillPackage.files) {
|
|
3277
|
-
const absPath =
|
|
4166
|
+
const absPath = resolve10(basePath, file.relativePath);
|
|
3278
4167
|
mkdirSync8(dirname10(absPath), { recursive: true });
|
|
3279
4168
|
writeFileSync8(absPath, file.content + "\n", "utf-8");
|
|
3280
4169
|
}
|
|
@@ -3285,8 +4174,8 @@ var installSkillPackages = (basePath, packages) => {
|
|
|
3285
4174
|
var removeDirectories = (basePath, relativeDirs) => {
|
|
3286
4175
|
const removed = [];
|
|
3287
4176
|
for (const relativeDir of relativeDirs) {
|
|
3288
|
-
const absPath =
|
|
3289
|
-
if (!
|
|
4177
|
+
const absPath = resolve10(basePath, relativeDir);
|
|
4178
|
+
if (!existsSync7(absPath)) continue;
|
|
3290
4179
|
rmSync4(absPath, { recursive: true, force: true });
|
|
3291
4180
|
removed.push(relativeDir);
|
|
3292
4181
|
}
|
|
@@ -3465,14 +4354,14 @@ var skillUninstallCommand = async (skillId) => {
|
|
|
3465
4354
|
|
|
3466
4355
|
// src/commands/subagent.ts
|
|
3467
4356
|
import * as p8 from "@clack/prompts";
|
|
3468
|
-
import { existsSync as
|
|
4357
|
+
import { existsSync as existsSync9, rmSync as rmSync7 } from "fs";
|
|
3469
4358
|
|
|
3470
4359
|
// src/lib/subagent-install.ts
|
|
3471
|
-
import { existsSync as
|
|
3472
|
-
import { dirname as dirname11, isAbsolute as isAbsolute3, relative as relative3, resolve as
|
|
4360
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync9, rmSync as rmSync6, writeFileSync as writeFileSync9 } from "fs";
|
|
4361
|
+
import { dirname as dirname11, isAbsolute as isAbsolute3, relative as relative3, resolve as resolve11 } from "path";
|
|
3473
4362
|
var resolveInsideBasePath = (basePath, relativePath) => {
|
|
3474
|
-
const absBasePath =
|
|
3475
|
-
const absPath =
|
|
4363
|
+
const absBasePath = resolve11(basePath);
|
|
4364
|
+
const absPath = resolve11(absBasePath, relativePath);
|
|
3476
4365
|
const fromBase = relative3(absBasePath, absPath);
|
|
3477
4366
|
if (fromBase.length === 0 || fromBase.startsWith("..") || isAbsolute3(fromBase)) {
|
|
3478
4367
|
throw new Error(`Subagent path escapes AI_OPS_HOME: ${relativePath}`);
|
|
@@ -3484,7 +4373,7 @@ var installSubagentPackages = (basePath, packages) => {
|
|
|
3484
4373
|
for (const subagentPackage of packages) {
|
|
3485
4374
|
for (const file of subagentPackage.files) {
|
|
3486
4375
|
const absPath = resolveInsideBasePath(basePath, file.relativePath);
|
|
3487
|
-
if (
|
|
4376
|
+
if (existsSync8(absPath)) {
|
|
3488
4377
|
rmSync6(absPath, { recursive: true, force: true });
|
|
3489
4378
|
}
|
|
3490
4379
|
mkdirSync9(dirname11(absPath), { recursive: true });
|
|
@@ -3498,7 +4387,7 @@ var removeSubagentFiles = (basePath, relativePaths) => {
|
|
|
3498
4387
|
const removed = [];
|
|
3499
4388
|
for (const relativePath of relativePaths) {
|
|
3500
4389
|
const absPath = resolveInsideBasePath(basePath, relativePath);
|
|
3501
|
-
if (!
|
|
4390
|
+
if (!existsSync8(absPath)) continue;
|
|
3502
4391
|
rmSync6(absPath, { recursive: true, force: true });
|
|
3503
4392
|
removed.push(relativePath);
|
|
3504
4393
|
}
|
|
@@ -3560,7 +4449,7 @@ var writeUserSubagentState = (params) => {
|
|
|
3560
4449
|
};
|
|
3561
4450
|
var readInstalledSubagents = (basePath) => readSubagentManifest(resolveSubagentManifestPath(basePath))?.subagents ?? [];
|
|
3562
4451
|
var warnMissingSkills = (requiredSkills) => {
|
|
3563
|
-
const missing = requiredSkills.filter((skill) => !
|
|
4452
|
+
const missing = requiredSkills.filter((skill) => !existsSync9(skill.path));
|
|
3564
4453
|
if (missing.length === 0) {
|
|
3565
4454
|
return;
|
|
3566
4455
|
}
|
|
@@ -3871,13 +4760,13 @@ var parseMax = (max) => {
|
|
|
3871
4760
|
}
|
|
3872
4761
|
return parsed;
|
|
3873
4762
|
};
|
|
3874
|
-
var readStdin = async () => new Promise((
|
|
4763
|
+
var readStdin = async () => new Promise((resolve12, reject) => {
|
|
3875
4764
|
let raw = "";
|
|
3876
4765
|
process.stdin.setEncoding("utf-8");
|
|
3877
4766
|
process.stdin.on("data", (chunk) => {
|
|
3878
4767
|
raw += chunk;
|
|
3879
4768
|
});
|
|
3880
|
-
process.stdin.on("end", () =>
|
|
4769
|
+
process.stdin.on("end", () => resolve12(raw));
|
|
3881
4770
|
process.stdin.on("error", reject);
|
|
3882
4771
|
});
|
|
3883
4772
|
var reportContextPromotionError = (error) => {
|
|
@@ -3978,8 +4867,8 @@ var contextPromotionPostToolUseHookCommand = async () => {
|
|
|
3978
4867
|
|
|
3979
4868
|
// src/commands/codex-hook.ts
|
|
3980
4869
|
import * as p11 from "@clack/prompts";
|
|
3981
|
-
import { existsSync as
|
|
3982
|
-
import { join as
|
|
4870
|
+
import { existsSync as existsSync10 } from "fs";
|
|
4871
|
+
import { join as join16 } from "path";
|
|
3983
4872
|
var CONTEXT_PROMOTION_REVIEW_SKILL_ID = "context-promotion-review";
|
|
3984
4873
|
var resolveCodexHomePath = () => {
|
|
3985
4874
|
const codexHome = process.env.CODEX_HOME;
|
|
@@ -4017,7 +4906,7 @@ var resolveContextPromotionReviewSkill = () => {
|
|
|
4017
4906
|
};
|
|
4018
4907
|
var hasInstalledContextPromotionReviewSkill = (basePath) => {
|
|
4019
4908
|
const installedSkill = findInstalledSkill(readInstalledSkills2(basePath), CONTEXT_PROMOTION_REVIEW_SKILL_ID);
|
|
4020
|
-
return installedSkill?.tools.includes(SKILL_TOOL.CODEX) === true &&
|
|
4909
|
+
return installedSkill?.tools.includes(SKILL_TOOL.CODEX) === true && existsSync10(join16(basePath, ".agents/skills/context-promotion-review/SKILL.md"));
|
|
4021
4910
|
};
|
|
4022
4911
|
var ensureContextPromotionReviewSkill = (basePath) => {
|
|
4023
4912
|
const skill = resolveContextPromotionReviewSkill();
|
|
@@ -4031,7 +4920,7 @@ var ensureContextPromotionReviewSkill = (basePath) => {
|
|
|
4031
4920
|
skill,
|
|
4032
4921
|
requestedTools
|
|
4033
4922
|
});
|
|
4034
|
-
const alreadyInstalled = existingInstalledSkill?.sourceHash === installedSkill.sourceHash && existingInstalledSkill.tools.includes(SKILL_TOOL.CODEX) &&
|
|
4923
|
+
const alreadyInstalled = existingInstalledSkill?.sourceHash === installedSkill.sourceHash && existingInstalledSkill.tools.includes(SKILL_TOOL.CODEX) && existsSync10(join16(basePath, ".agents/skills/context-promotion-review/SKILL.md"));
|
|
4035
4924
|
if (alreadyInstalled) {
|
|
4036
4925
|
return { changed: false, installedSkill };
|
|
4037
4926
|
}
|
|
@@ -4094,8 +4983,8 @@ var codexHookUninstallCommand = async (hookId) => {
|
|
|
4094
4983
|
|
|
4095
4984
|
// src/commands/integration.ts
|
|
4096
4985
|
import * as p12 from "@clack/prompts";
|
|
4097
|
-
import { existsSync as
|
|
4098
|
-
import { join as
|
|
4986
|
+
import { existsSync as existsSync11, rmSync as rmSync8 } from "fs";
|
|
4987
|
+
import { join as join17 } from "path";
|
|
4099
4988
|
var CODEX_HOOK_DEFINITIONS = [CONTEXT_PROMOTION_CODEX_HOOK, PC_CODEX_HOOK];
|
|
4100
4989
|
var resolveCodexHomePath2 = () => {
|
|
4101
4990
|
const codexHome = process.env.CODEX_HOME;
|
|
@@ -4168,13 +5057,13 @@ var reportIntegrationError = (error) => {
|
|
|
4168
5057
|
p12.log.error(message);
|
|
4169
5058
|
process.exitCode = 1;
|
|
4170
5059
|
};
|
|
4171
|
-
var readStdin2 = async () => new Promise((
|
|
5060
|
+
var readStdin2 = async () => new Promise((resolve12, reject) => {
|
|
4172
5061
|
let raw = "";
|
|
4173
5062
|
process.stdin.setEncoding("utf-8");
|
|
4174
5063
|
process.stdin.on("data", (chunk) => {
|
|
4175
5064
|
raw += chunk;
|
|
4176
5065
|
});
|
|
4177
|
-
process.stdin.on("end", () =>
|
|
5066
|
+
process.stdin.on("end", () => resolve12(raw));
|
|
4178
5067
|
process.stdin.on("error", reject);
|
|
4179
5068
|
});
|
|
4180
5069
|
var readInstalledSkills3 = (basePath) => (readSkillRegistry(resolveSkillRegistryPath(basePath))?.skills ?? []).map((installedSkill) => ({
|
|
@@ -4190,7 +5079,7 @@ var resolveSkillById2 = (skillId) => {
|
|
|
4190
5079
|
};
|
|
4191
5080
|
var hasInstalledCodexSkill = (params) => {
|
|
4192
5081
|
const installedSkill = findInstalledSkill(readInstalledSkills3(params.basePath), params.skillId);
|
|
4193
|
-
return installedSkill?.tools.includes(SKILL_TOOL.CODEX) === true &&
|
|
5082
|
+
return installedSkill?.tools.includes(SKILL_TOOL.CODEX) === true && existsSync11(join17(params.basePath, ".agents/skills", params.skillId, "SKILL.md"));
|
|
4194
5083
|
};
|
|
4195
5084
|
var writeUserSkillState2 = (params) => {
|
|
4196
5085
|
const registryPath = resolveSkillRegistryPath(params.basePath);
|
|
@@ -4218,7 +5107,7 @@ var ensureSkillComponent = (params) => {
|
|
|
4218
5107
|
skill,
|
|
4219
5108
|
requestedTools
|
|
4220
5109
|
});
|
|
4221
|
-
const alreadyCurrent = existingInstalledSkill?.sourceHash === installedSkill.sourceHash && existingInstalledSkill.tools.includes(SKILL_TOOL.CODEX) &&
|
|
5110
|
+
const alreadyCurrent = existingInstalledSkill?.sourceHash === installedSkill.sourceHash && existingInstalledSkill.tools.includes(SKILL_TOOL.CODEX) && existsSync11(join17(params.basePath, ".agents/skills", params.skillId, "SKILL.md"));
|
|
4222
5111
|
if (alreadyCurrent) {
|
|
4223
5112
|
return {
|
|
4224
5113
|
type: INTEGRATION_COMPONENT_TYPE.SKILL,
|
|
@@ -4480,6 +5369,8 @@ program.command("update").description("project operating layer \uAC31\uC2E0").op
|
|
|
4480
5369
|
program.command("diff").description("project operating layer drift \uBE44\uAD50").action(() => diffCommand());
|
|
4481
5370
|
program.command("audit").description("project operating layer \uC0C1\uD0DC \uAC80\uC0AC").action(() => auditCommand());
|
|
4482
5371
|
program.command("uninstall").description("project operating layer \uC81C\uAC70").option("--yes", "\uD655\uC778 \uD504\uB86C\uD504\uD2B8 \uC5C6\uC774 \uC81C\uAC70", false).action((opts) => uninstallCommand(opts));
|
|
5372
|
+
var studioCommand = program.command("studio").description("ai-ops Studio read-only helpers");
|
|
5373
|
+
studioCommand.command("snapshot").description("Studio read-only snapshot JSON \uC0DD\uC131").requiredOption("--json", "JSON\uC73C\uB85C \uCD9C\uB825").action((opts) => studioSnapshotCommand(opts));
|
|
4483
5374
|
var skillCommand = program.command("skill").description("\uC5D0\uC774\uC804\uD2B8 skill \uC124\uCE58/\uC870\uD68C/\uAC31\uC2E0");
|
|
4484
5375
|
var applySkillInstallOptions = (command) => command.option("--tool <tool...>", "\uB300\uC0C1 \uB3C4\uAD6C \uC9C0\uC815");
|
|
4485
5376
|
skillCommand.command("list").description("\uC0AC\uC6A9 \uAC00\uB2A5\uD55C skill \uBAA9\uB85D").action(() => skillListCommand());
|