ai-ops-cli 1.3.0 → 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/README.ko.md +13 -2
- package/README.md +13 -2
- package/data/context-layer/AGENTS.md +4 -3
- package/data/context-layer/docs/agent/rules/00-agent-baseline.md +2 -1
- package/data/context-layer/docs/agent/terminology.md +39 -0
- package/data/context-layer/docs/business/terminology.md +61 -0
- package/data/packs/spec-lifecycle/docs/specs/README.ko.md +1 -0
- package/data/packs/spec-lifecycle/docs/specs/README.md +1 -0
- package/data/skills/skill-registry.json +2 -2
- package/data/skills/task-skills/context-promotion-review/SKILL.md +26 -16
- package/data/skills/task-skills/{spec-shared-glossary-sync → project-terminology-sync}/SKILL.md +25 -16
- package/data/skills/task-skills/project-terminology-sync/agents/openai.yaml +6 -0
- package/data/skills/task-skills/{spec-shared-glossary-sync → project-terminology-sync}/references/checklist.md +5 -5
- package/data/skills/task-skills/{spec-shared-glossary-sync → project-terminology-sync}/references/template.md +19 -18
- package/data/skills/task-skills/spec-baseline-sync/SKILL.md +4 -4
- package/data/skills/task-skills/spec-product-01-idea-to-brief/SKILL.md +3 -3
- package/data/skills/task-skills/spec-product-02-brief-to-technical-context/SKILL.md +3 -3
- package/data/skills/task-skills/spec-product-03-brief-to-product-spec/SKILL.md +3 -3
- package/data/skills/task-skills/spec-product-05-spec-to-work-packets/SKILL.md +3 -3
- package/dist/bin/index.js +1210 -316
- package/dist/bin/index.js.map +1 -1
- package/package.json +1 -1
- package/data/skills/task-skills/spec-shared-glossary-sync/agents/openai.yaml +0 -6
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";
|
|
@@ -889,18 +1039,21 @@ var TEMPLATE_PATHS = [
|
|
|
889
1039
|
"GEMINI.md",
|
|
890
1040
|
"CLAUDE.md",
|
|
891
1041
|
"docs/agent/workflow.md",
|
|
1042
|
+
"docs/agent/terminology.md",
|
|
892
1043
|
"docs/agent/rules/00-agent-baseline.md",
|
|
893
1044
|
"docs/agent/rules/routing-rules.md",
|
|
894
1045
|
"docs/agent/rules/doc-update-rules.md",
|
|
895
1046
|
"docs/agent/rules/stop-rules.md",
|
|
896
1047
|
"docs/agent/checks/impact-checklist.md",
|
|
897
1048
|
"docs/agent/maps/codebase-map.md",
|
|
1049
|
+
"docs/business/terminology.md",
|
|
898
1050
|
"docs/business/business-rules.md",
|
|
899
1051
|
"docs/docs-status.md"
|
|
900
1052
|
];
|
|
901
1053
|
var PROJECT_OWNED_PATHS = /* @__PURE__ */ new Set([
|
|
902
1054
|
"docs/docs-status.md",
|
|
903
1055
|
"docs/agent/maps/codebase-map.md",
|
|
1056
|
+
"docs/business/terminology.md",
|
|
904
1057
|
"docs/business/business-rules.md"
|
|
905
1058
|
]);
|
|
906
1059
|
var RESERVED_DOCUMENT_WARNINGS = [
|
|
@@ -1573,24 +1726,914 @@ var removeEmptyDirs = (basePath, relativePaths) => {
|
|
|
1573
1726
|
}
|
|
1574
1727
|
}
|
|
1575
1728
|
};
|
|
1576
|
-
var uninstallProjectLayer = (basePath, manifest) => {
|
|
1577
|
-
const managedResults = manifest.managed_files.map((file) => removeManagedProjectFile(basePath, file.path));
|
|
1578
|
-
const projectResults = manifest.project_files.map((file) => removeCreateOnlyProjectFile(basePath, file));
|
|
1579
|
-
const packResults = manifest.packs.flatMap(
|
|
1580
|
-
(pack) => [...pack.documents, ...pack.files].map((file) => removePackOwnedFile(basePath, file))
|
|
1581
|
-
);
|
|
1582
|
-
const stateFiles = [PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH, PROJECT_LAYER_MANIFEST_RELATIVE_PATH];
|
|
1583
|
-
for (const stateFile of stateFiles) {
|
|
1584
|
-
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
|
+
};
|
|
1585
2536
|
}
|
|
1586
|
-
const
|
|
1587
|
-
|
|
1588
|
-
|
|
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
|
+
});
|
|
1589
2632
|
};
|
|
1590
2633
|
|
|
1591
2634
|
// src/core/pack.ts
|
|
1592
|
-
import { existsSync as
|
|
1593
|
-
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";
|
|
1594
2637
|
var PACK_REGISTRY_FILENAME = "pack-registry.json";
|
|
1595
2638
|
var SPEC_LIFECYCLE_PACK_ID = "spec-lifecycle";
|
|
1596
2639
|
var PACK_INSTALL_ROOT = "docs/specs/";
|
|
@@ -1598,9 +2641,9 @@ var RESERVED_DOCUMENT_WARNINGS2 = [
|
|
|
1598
2641
|
"\uD310\uB2E8 \uADFC\uAC70\uB85C \uC0AC\uC6A9\uD558\uC9C0 \uB9C8\uC138\uC694",
|
|
1599
2642
|
"Do not use this document as current decision-making evidence"
|
|
1600
2643
|
];
|
|
1601
|
-
var DEFAULT_PACKS_DIR =
|
|
2644
|
+
var DEFAULT_PACKS_DIR = join11(COMPILER_DATA_DIR, "packs");
|
|
1602
2645
|
var includesReservedDocumentWarning2 = (content) => RESERVED_DOCUMENT_WARNINGS2.some((warning) => content.includes(warning));
|
|
1603
|
-
var readPackCatalog = (packsDir) => PackCatalogSchema.parse(JSON.parse(
|
|
2646
|
+
var readPackCatalog = (packsDir) => PackCatalogSchema.parse(JSON.parse(readFileSync9(join11(packsDir, PACK_REGISTRY_FILENAME), "utf-8")));
|
|
1604
2647
|
var assertPackInstallPath = (path) => {
|
|
1605
2648
|
if (!isSafeProjectLayerPath(path) || !path.startsWith(PACK_INSTALL_ROOT)) {
|
|
1606
2649
|
throw new Error(`Unsafe pack path: ${path}`);
|
|
@@ -1609,16 +2652,16 @@ var assertPackInstallPath = (path) => {
|
|
|
1609
2652
|
var readPackSourceFiles = (packDir) => {
|
|
1610
2653
|
const files = [];
|
|
1611
2654
|
const walk = (relativeDir = "") => {
|
|
1612
|
-
const absoluteDir = relativeDir.length > 0 ?
|
|
2655
|
+
const absoluteDir = relativeDir.length > 0 ? join11(packDir, relativeDir) : packDir;
|
|
1613
2656
|
const entries = readdirSync4(absoluteDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
1614
2657
|
for (const entry of entries) {
|
|
1615
|
-
const nextRelativePath = relativeDir.length > 0 ?
|
|
2658
|
+
const nextRelativePath = relativeDir.length > 0 ? join11(relativeDir, entry.name) : entry.name;
|
|
1616
2659
|
if (entry.isDirectory()) {
|
|
1617
2660
|
walk(nextRelativePath);
|
|
1618
2661
|
continue;
|
|
1619
2662
|
}
|
|
1620
2663
|
assertPackInstallPath(nextRelativePath);
|
|
1621
|
-
const content =
|
|
2664
|
+
const content = readFileSync9(join11(packDir, nextRelativePath), "utf-8");
|
|
1622
2665
|
files.push({
|
|
1623
2666
|
path: nextRelativePath,
|
|
1624
2667
|
content,
|
|
@@ -1653,8 +2696,8 @@ var loadAllPacks = (packsDir) => {
|
|
|
1653
2696
|
if (entry.id !== SPEC_LIFECYCLE_PACK_ID) {
|
|
1654
2697
|
throw new Error(`Unsupported pack id: ${entry.id}`);
|
|
1655
2698
|
}
|
|
1656
|
-
const packDir =
|
|
1657
|
-
const relativeFromPacks = relative2(
|
|
2699
|
+
const packDir = resolve7(packsDir, entry.source_path);
|
|
2700
|
+
const relativeFromPacks = relative2(resolve7(packsDir), packDir);
|
|
1658
2701
|
if (relativeFromPacks.length === 0 || relativeFromPacks.startsWith("..") || isAbsolute2(relativeFromPacks)) {
|
|
1659
2702
|
throw new Error(`Pack source path escapes packs dir: ${entry.source_path}`);
|
|
1660
2703
|
}
|
|
@@ -1676,11 +2719,11 @@ var resolvePackById = (packsDir, packId) => {
|
|
|
1676
2719
|
return pack;
|
|
1677
2720
|
};
|
|
1678
2721
|
var serializePackFileContent = (content) => content.length === 0 ? "" : content.trimEnd() + "\n";
|
|
1679
|
-
var readProjectFileHash = (basePath, relativePath) => computeHash([
|
|
2722
|
+
var readProjectFileHash = (basePath, relativePath) => computeHash([readFileSync9(resolveProjectLayerFilePath(basePath, relativePath), "utf-8").trimEnd()]);
|
|
1680
2723
|
var writePackFile = (basePath, file) => {
|
|
1681
2724
|
const absolutePath = resolveProjectLayerFilePath(basePath, file.path);
|
|
1682
|
-
|
|
1683
|
-
|
|
2725
|
+
mkdirSync6(dirname8(absolutePath), { recursive: true });
|
|
2726
|
+
writeFileSync6(absolutePath, serializePackFileContent(file.content), "utf-8");
|
|
1684
2727
|
};
|
|
1685
2728
|
var buildPackFileRecords = (files) => files.map((file) => ({
|
|
1686
2729
|
path: file.path,
|
|
@@ -1710,7 +2753,7 @@ var applyPackSourceFiles = (params) => {
|
|
|
1710
2753
|
for (const file of sourceFiles) {
|
|
1711
2754
|
const absolutePath = resolveProjectLayerFilePath(params.basePath, file.path);
|
|
1712
2755
|
const previous = previousByPath.get(file.path);
|
|
1713
|
-
if (!
|
|
2756
|
+
if (!existsSync4(absolutePath)) {
|
|
1714
2757
|
writePackFile(params.basePath, file);
|
|
1715
2758
|
written.push(file.path);
|
|
1716
2759
|
continue;
|
|
@@ -1734,7 +2777,7 @@ var applyPackSourceFiles = (params) => {
|
|
|
1734
2777
|
continue;
|
|
1735
2778
|
}
|
|
1736
2779
|
const absolutePath = resolveProjectLayerFilePath(params.basePath, previous.path);
|
|
1737
|
-
if (!
|
|
2780
|
+
if (!existsSync4(absolutePath)) {
|
|
1738
2781
|
notFound.push(previous.path);
|
|
1739
2782
|
continue;
|
|
1740
2783
|
}
|
|
@@ -1753,7 +2796,7 @@ var removePackFiles = (basePath, record) => {
|
|
|
1753
2796
|
const notFound = [];
|
|
1754
2797
|
for (const file of [...record.documents, ...record.files]) {
|
|
1755
2798
|
const absolutePath = resolveProjectLayerFilePath(basePath, file.path);
|
|
1756
|
-
if (!
|
|
2799
|
+
if (!existsSync4(absolutePath)) {
|
|
1757
2800
|
notFound.push(file.path);
|
|
1758
2801
|
continue;
|
|
1759
2802
|
}
|
|
@@ -1767,12 +2810,12 @@ var removePackFiles = (basePath, record) => {
|
|
|
1767
2810
|
return { written: [], refreshed: [], preserved, deleted, notFound };
|
|
1768
2811
|
};
|
|
1769
2812
|
var removeEmptyDirs2 = (basePath, relativePaths) => {
|
|
1770
|
-
const dirs = [...new Set(relativePaths.map((path) =>
|
|
2813
|
+
const dirs = [...new Set(relativePaths.map((path) => dirname8(path)).filter((dir) => dir !== "."))].sort(
|
|
1771
2814
|
(a, b) => b.length - a.length
|
|
1772
2815
|
);
|
|
1773
2816
|
for (const dir of dirs) {
|
|
1774
2817
|
const absoluteDir = resolveProjectLayerFilePath(basePath, dir);
|
|
1775
|
-
if (!
|
|
2818
|
+
if (!existsSync4(absoluteDir)) {
|
|
1776
2819
|
continue;
|
|
1777
2820
|
}
|
|
1778
2821
|
try {
|
|
@@ -1888,7 +2931,7 @@ var diffProjectLayerPack = (params) => {
|
|
|
1888
2931
|
}
|
|
1889
2932
|
for (const file of [...record.documents, ...record.files]) {
|
|
1890
2933
|
const absolutePath = resolveProjectLayerFilePath(params.basePath, file.path);
|
|
1891
|
-
if (!
|
|
2934
|
+
if (!existsSync4(absolutePath)) {
|
|
1892
2935
|
issues.push(packIssue("error", "missing-file", `\uD30C\uC77C \uC5C6\uC74C: ${file.path}`));
|
|
1893
2936
|
}
|
|
1894
2937
|
}
|
|
@@ -1899,21 +2942,21 @@ var diffProjectLayerPack = (params) => {
|
|
|
1899
2942
|
// src/core/context-promotion.ts
|
|
1900
2943
|
import { createHash as createHash2 } from "crypto";
|
|
1901
2944
|
import { execFileSync } from "child_process";
|
|
1902
|
-
import { existsSync as
|
|
1903
|
-
import { dirname as
|
|
1904
|
-
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";
|
|
1905
2948
|
|
|
1906
2949
|
// src/core/tool-use-hook.ts
|
|
1907
|
-
import { z as
|
|
1908
|
-
var HookToolInputSchema =
|
|
1909
|
-
command:
|
|
2950
|
+
import { z as z13 } from "zod";
|
|
2951
|
+
var HookToolInputSchema = z13.object({
|
|
2952
|
+
command: z13.string().optional()
|
|
1910
2953
|
}).passthrough();
|
|
1911
|
-
var ToolUseHookInputSchema =
|
|
1912
|
-
hook_event_name:
|
|
1913
|
-
cwd:
|
|
1914
|
-
tool_name:
|
|
1915
|
-
tool_input:
|
|
1916
|
-
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()
|
|
1917
2960
|
}).passthrough();
|
|
1918
2961
|
var SHELL_CONTROL_TOKENS = /* @__PURE__ */ new Set(["&&", "||", ";", "|", "(", ")"]);
|
|
1919
2962
|
var SHELL_SCRIPT_FLAGS = /* @__PURE__ */ new Set(["-c", "-lc"]);
|
|
@@ -2044,7 +3087,7 @@ var isGitCommitCommand = (command) => {
|
|
|
2044
3087
|
(segment) => segmentInvokesGitCommit(segment) || segmentInvokesShellScriptWithGitCommit(segment)
|
|
2045
3088
|
);
|
|
2046
3089
|
};
|
|
2047
|
-
var
|
|
3090
|
+
var isJsonRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2048
3091
|
var numberField = (record, keys) => {
|
|
2049
3092
|
for (const key of keys) {
|
|
2050
3093
|
const value = record[key];
|
|
@@ -2088,7 +3131,7 @@ var toolResponseIndicatesFailure = (toolResponse) => {
|
|
|
2088
3131
|
if (typeof toolResponse === "string") {
|
|
2089
3132
|
return stringIndicatesGitCommitFailureOrSuccess(toolResponse) === true;
|
|
2090
3133
|
}
|
|
2091
|
-
if (!
|
|
3134
|
+
if (!isJsonRecord3(toolResponse)) {
|
|
2092
3135
|
return false;
|
|
2093
3136
|
}
|
|
2094
3137
|
const success = booleanField(toolResponse, ["success", "ok"]);
|
|
@@ -2130,35 +3173,35 @@ var CONTEXT_PROMOTION_SCOPE = {
|
|
|
2130
3173
|
PROJECT_LOCAL: "project-local",
|
|
2131
3174
|
GLOBAL: "global"
|
|
2132
3175
|
};
|
|
2133
|
-
var ContextPromotionDecisionSchema =
|
|
2134
|
-
|
|
2135
|
-
|
|
3176
|
+
var ContextPromotionDecisionSchema = z14.union([
|
|
3177
|
+
z14.literal(CONTEXT_PROMOTION_DECISION.PROMOTED),
|
|
3178
|
+
z14.literal(CONTEXT_PROMOTION_DECISION.NO_PROMOTION)
|
|
2136
3179
|
]);
|
|
2137
|
-
var ContextPromotionScopeSchema =
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
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)
|
|
2141
3184
|
]);
|
|
2142
|
-
var ContextPromotionReceiptSchema =
|
|
2143
|
-
fingerprint:
|
|
2144
|
-
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(),
|
|
2145
3188
|
decision: ContextPromotionDecisionSchema,
|
|
2146
|
-
scopes:
|
|
2147
|
-
targets:
|
|
2148
|
-
summary:
|
|
2149
|
-
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)
|
|
2150
3193
|
}).strict();
|
|
2151
|
-
var ContextPromotionReceiptIndexSchema =
|
|
2152
|
-
schemaVersion:
|
|
2153
|
-
kind:
|
|
2154
|
-
projectKey:
|
|
2155
|
-
projectRoot:
|
|
2156
|
-
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)
|
|
2157
3200
|
}).strict();
|
|
2158
3201
|
var RECEIPT_INDEX_FILENAME = "receipts-index.json";
|
|
2159
3202
|
var DEFAULT_PRUNE_MAX = 50;
|
|
2160
3203
|
var hashHex = (parts, length) => createHash2("sha256").update(parts.join("\0")).digest("hex").slice(0, length);
|
|
2161
|
-
var buildContextPromotionProjectKey = (gitRoot) => hashHex([
|
|
3204
|
+
var buildContextPromotionProjectKey = (gitRoot) => hashHex([resolve8(gitRoot)], 12);
|
|
2162
3205
|
var runGit = (cwd, args) => execFileSync("git", [...args], {
|
|
2163
3206
|
cwd,
|
|
2164
3207
|
encoding: "utf-8",
|
|
@@ -2183,13 +3226,13 @@ var readUntrackedFingerprintParts = (gitRoot) => {
|
|
|
2183
3226
|
const raw = runGit(gitRoot, ["ls-files", "--others", "--exclude-standard", "-z"]);
|
|
2184
3227
|
const paths = raw.split("\0").filter((path) => path.length > 0).sort((a, b) => a.localeCompare(b));
|
|
2185
3228
|
return paths.map((relativePath) => {
|
|
2186
|
-
const absolutePath =
|
|
3229
|
+
const absolutePath = join12(gitRoot, relativePath);
|
|
2187
3230
|
try {
|
|
2188
3231
|
const stat = statSync(absolutePath);
|
|
2189
3232
|
if (!stat.isFile()) {
|
|
2190
3233
|
return `${relativePath}:non-file`;
|
|
2191
3234
|
}
|
|
2192
|
-
const content =
|
|
3235
|
+
const content = readFileSync10(absolutePath);
|
|
2193
3236
|
return `${relativePath}:${createHash2("sha256").update(content).digest("hex")}`;
|
|
2194
3237
|
} catch {
|
|
2195
3238
|
throw new Error(`Unable to read untracked path for context promotion fingerprint: ${relativePath}`);
|
|
@@ -2203,15 +3246,15 @@ var readTrackedWorkingTreeFingerprintParts = (gitRoot) => {
|
|
|
2203
3246
|
return [
|
|
2204
3247
|
`raw:${rawDiff}`,
|
|
2205
3248
|
...paths.map((relativePath) => {
|
|
2206
|
-
const absolutePath =
|
|
2207
|
-
if (!
|
|
3249
|
+
const absolutePath = join12(gitRoot, relativePath);
|
|
3250
|
+
if (!existsSync5(absolutePath)) {
|
|
2208
3251
|
return `${relativePath}:deleted`;
|
|
2209
3252
|
}
|
|
2210
3253
|
const stat = statSync(absolutePath);
|
|
2211
3254
|
if (!stat.isFile()) {
|
|
2212
3255
|
return `${relativePath}:non-file`;
|
|
2213
3256
|
}
|
|
2214
|
-
const content =
|
|
3257
|
+
const content = readFileSync10(absolutePath);
|
|
2215
3258
|
return `${relativePath}:${createHash2("sha256").update(content).digest("hex")}`;
|
|
2216
3259
|
})
|
|
2217
3260
|
];
|
|
@@ -2229,19 +3272,19 @@ var computeContextPromotionFingerprint = (gitRoot) => hashHex(
|
|
|
2229
3272
|
],
|
|
2230
3273
|
16
|
|
2231
3274
|
);
|
|
2232
|
-
var resolveContextPromotionReceiptIndexPath = (params) =>
|
|
3275
|
+
var resolveContextPromotionReceiptIndexPath = (params) => join12(params.userBasePath, ".ai-ops", "context-promotion", "projects", params.projectKey, RECEIPT_INDEX_FILENAME);
|
|
2233
3276
|
var parseContextPromotionReceiptIndex = (json) => ContextPromotionReceiptIndexSchema.parse(JSON.parse(json));
|
|
2234
3277
|
var serializeContextPromotionReceiptIndex = (index) => JSON.stringify(index, null, 2) + "\n";
|
|
2235
3278
|
var readContextPromotionReceiptIndex = (indexPath) => {
|
|
2236
3279
|
try {
|
|
2237
|
-
return parseContextPromotionReceiptIndex(
|
|
3280
|
+
return parseContextPromotionReceiptIndex(readFileSync10(indexPath, "utf-8"));
|
|
2238
3281
|
} catch {
|
|
2239
3282
|
return null;
|
|
2240
3283
|
}
|
|
2241
3284
|
};
|
|
2242
3285
|
var writeContextPromotionReceiptIndex = (indexPath, index) => {
|
|
2243
|
-
|
|
2244
|
-
|
|
3286
|
+
mkdirSync7(dirname9(indexPath), { recursive: true });
|
|
3287
|
+
writeFileSync7(indexPath, serializeContextPromotionReceiptIndex(index), "utf-8");
|
|
2245
3288
|
};
|
|
2246
3289
|
var buildEmptyReceiptIndex = (params) => ({
|
|
2247
3290
|
schemaVersion: 1,
|
|
@@ -2289,9 +3332,9 @@ var pruneContextPromotionReceipts = (params) => {
|
|
|
2289
3332
|
writeContextPromotionReceiptIndex(params.indexPath, nextIndex);
|
|
2290
3333
|
return nextIndex;
|
|
2291
3334
|
};
|
|
2292
|
-
var hasContextPromotionLayer = (gitRoot) =>
|
|
3335
|
+
var hasContextPromotionLayer = (gitRoot) => existsSync5(join12(gitRoot, PROJECT_LAYER_CONTEXT_INDEX_RELATIVE_PATH));
|
|
2293
3336
|
var getContextPromotionStatus = (params) => {
|
|
2294
|
-
const cwd =
|
|
3337
|
+
const cwd = resolve8(params.cwd);
|
|
2295
3338
|
const gitRoot = resolveContextPromotionGitRoot(cwd);
|
|
2296
3339
|
if (!gitRoot) {
|
|
2297
3340
|
return {
|
|
@@ -2380,24 +3423,28 @@ var buildContextPromotionReviewPrompt = (status) => {
|
|
|
2380
3423
|
const projectRoot = status.gitRoot ?? status.cwd;
|
|
2381
3424
|
const cdCommand = `cd ${JSON.stringify(projectRoot)}`;
|
|
2382
3425
|
return [
|
|
2383
|
-
"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.",
|
|
2384
3427
|
"",
|
|
2385
3428
|
`Project root: ${projectRoot}`,
|
|
2386
3429
|
"This project root is authoritative for this review.",
|
|
2387
3430
|
"",
|
|
2388
|
-
"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.",
|
|
2389
3432
|
"",
|
|
2390
3433
|
"Scope boundary:",
|
|
2391
3434
|
`- Before inspecting files, anchor shell work in the project root above. If needed, run \`${cdCommand}\` first.`,
|
|
2392
3435
|
"- Do not inspect other repositories, parent directories, or earlier conversation workspaces.",
|
|
2393
3436
|
"- Do not search the web or external documentation for this review.",
|
|
2394
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.",
|
|
2395
|
-
"- 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.",
|
|
2396
3439
|
"",
|
|
2397
3440
|
"Review requirements:",
|
|
2398
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`.",
|
|
2399
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.",
|
|
2400
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.",
|
|
2401
3448
|
"- Classify candidates as `core`, `project-local`, `global`, `already-covered`, or `no-promotion`.",
|
|
2402
3449
|
"- Ask the user before editing any file.",
|
|
2403
3450
|
"- If promotion is approved, edit only the approved context/global files, then stop for user inspection without committing.",
|
|
@@ -2453,9 +3500,9 @@ var evaluateContextPromotionPostToolUseHook = (params) => {
|
|
|
2453
3500
|
|
|
2454
3501
|
// src/core/pc-integration.ts
|
|
2455
3502
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
2456
|
-
import { existsSync as
|
|
2457
|
-
import { join as
|
|
2458
|
-
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 ?? "~"));
|
|
2459
3506
|
var pathContains = (parentPath, childPath) => {
|
|
2460
3507
|
const parent = normalizePath(parentPath);
|
|
2461
3508
|
const child = normalizePath(childPath);
|
|
@@ -2492,7 +3539,7 @@ var parseListField = (content, labels) => {
|
|
|
2492
3539
|
};
|
|
2493
3540
|
var readTextFileOrNull = (filePath) => {
|
|
2494
3541
|
try {
|
|
2495
|
-
return
|
|
3542
|
+
return readFileSync11(filePath, "utf-8");
|
|
2496
3543
|
} catch {
|
|
2497
3544
|
return null;
|
|
2498
3545
|
}
|
|
@@ -2517,11 +3564,11 @@ var readGitHead2 = (cwd) => {
|
|
|
2517
3564
|
}
|
|
2518
3565
|
};
|
|
2519
3566
|
var listWorkspaceStatePaths = (contextRoot) => {
|
|
2520
|
-
const workspacesDir =
|
|
2521
|
-
if (!
|
|
3567
|
+
const workspacesDir = join13(contextRoot, "workspaces");
|
|
3568
|
+
if (!existsSync6(workspacesDir)) {
|
|
2522
3569
|
return [];
|
|
2523
3570
|
}
|
|
2524
|
-
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));
|
|
2525
3572
|
};
|
|
2526
3573
|
var parseWorkspaceCandidate = (statePath) => {
|
|
2527
3574
|
const content = readTextFileOrNull(statePath);
|
|
@@ -2534,7 +3581,7 @@ var parseWorkspaceCandidate = (statePath) => {
|
|
|
2534
3581
|
}
|
|
2535
3582
|
const activeSection = extractSection(content, ["\uD65C\uC131 Workstream", "Active Workstream"]);
|
|
2536
3583
|
const activeWorkstreamId = parseListField(activeSection, ["ID", "Workstream ID", "Active Workstream"]);
|
|
2537
|
-
const workspaceDir =
|
|
3584
|
+
const workspaceDir = resolve9(statePath, "..");
|
|
2538
3585
|
const id = parseListField(content, ["\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 ID", "Workspace ID"]) ?? workspaceDir.split(sep).at(-1) ?? "unknown";
|
|
2539
3586
|
return {
|
|
2540
3587
|
id,
|
|
@@ -2564,11 +3611,11 @@ var parseRepoEntry = (entryPath) => {
|
|
|
2564
3611
|
};
|
|
2565
3612
|
};
|
|
2566
3613
|
var findCurrentEntry = (params) => {
|
|
2567
|
-
const reposDir =
|
|
2568
|
-
if (!
|
|
3614
|
+
const reposDir = join13(params.workspaceDir, "repos");
|
|
3615
|
+
if (!existsSync6(reposDir)) {
|
|
2569
3616
|
return null;
|
|
2570
3617
|
}
|
|
2571
|
-
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) => {
|
|
2572
3619
|
const paths = [entry.path, entry.gitRoot].filter((path) => path !== null);
|
|
2573
3620
|
return paths.some((path) => pathContains(path, params.cwd));
|
|
2574
3621
|
}).sort((a, b) => {
|
|
@@ -2620,7 +3667,7 @@ var parseLastConfirmedCommitHash = (params) => {
|
|
|
2620
3667
|
var getPcHandoffStatus = (params) => {
|
|
2621
3668
|
const cwd = normalizePath(params.cwd);
|
|
2622
3669
|
const contextRoot = normalizePath(params.contextRoot);
|
|
2623
|
-
if (!
|
|
3670
|
+
if (!existsSync6(contextRoot)) {
|
|
2624
3671
|
return {
|
|
2625
3672
|
cwd,
|
|
2626
3673
|
contextRoot,
|
|
@@ -2663,7 +3710,7 @@ var getPcHandoffStatus = (params) => {
|
|
|
2663
3710
|
skipReason: "active pc workstream not selected"
|
|
2664
3711
|
};
|
|
2665
3712
|
}
|
|
2666
|
-
const activeWorkstreamPath =
|
|
3713
|
+
const activeWorkstreamPath = join13(workspace.workspaceDir, "workstreams", `${workspace.activeWorkstreamId}.md`);
|
|
2667
3714
|
const activeWorkstreamContent = readTextFileOrNull(activeWorkstreamPath);
|
|
2668
3715
|
if (!activeWorkstreamContent) {
|
|
2669
3716
|
return {
|
|
@@ -2780,204 +3827,12 @@ var evaluatePcPostToolUseHook = (params) => {
|
|
|
2780
3827
|
return buildPostToolUseOutput2(buildPcDonePrompt({ status, head, gitRoot }));
|
|
2781
3828
|
};
|
|
2782
3829
|
|
|
2783
|
-
// src/core/codex-hook.ts
|
|
2784
|
-
import { existsSync as existsSync5, mkdirSync as mkdirSync7, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "fs";
|
|
2785
|
-
import { dirname as dirname9, join as join12 } from "path";
|
|
2786
|
-
var CONTEXT_PROMOTION_HOOK_ID = "context-promotion";
|
|
2787
|
-
var CONTEXT_PROMOTION_HOOK_COMMAND_MARKER = "context-promotion hook post-tool-use";
|
|
2788
|
-
var CONTEXT_PROMOTION_LEGACY_HOOK_COMMAND_MARKER = "context-promotion hook pre-tool-use";
|
|
2789
|
-
var CONTEXT_PROMOTION_DEFAULT_HOOK_COMMAND = `ai-ops ${CONTEXT_PROMOTION_HOOK_COMMAND_MARKER}`;
|
|
2790
|
-
var PC_HOOK_ID = "pc";
|
|
2791
|
-
var PC_HOOK_COMMAND_MARKER = "integration hook post-tool-use pc";
|
|
2792
|
-
var PC_DEFAULT_HOOK_COMMAND = `ai-ops ${PC_HOOK_COMMAND_MARKER}`;
|
|
2793
|
-
var PRE_TOOL_USE_EVENT = "PreToolUse";
|
|
2794
|
-
var POST_TOOL_USE_EVENT = "PostToolUse";
|
|
2795
|
-
var BASH_MATCHER = "^Bash$";
|
|
2796
|
-
var CONTEXT_PROMOTION_CODEX_HOOK = {
|
|
2797
|
-
id: CONTEXT_PROMOTION_HOOK_ID,
|
|
2798
|
-
commandMarker: CONTEXT_PROMOTION_HOOK_COMMAND_MARKER,
|
|
2799
|
-
legacyCommandMarkers: [CONTEXT_PROMOTION_LEGACY_HOOK_COMMAND_MARKER],
|
|
2800
|
-
defaultCommand: CONTEXT_PROMOTION_DEFAULT_HOOK_COMMAND,
|
|
2801
|
-
statusMessage: "Checking context promotion review"
|
|
2802
|
-
};
|
|
2803
|
-
var PC_CODEX_HOOK = {
|
|
2804
|
-
id: PC_HOOK_ID,
|
|
2805
|
-
commandMarker: PC_HOOK_COMMAND_MARKER,
|
|
2806
|
-
legacyCommandMarkers: [],
|
|
2807
|
-
defaultCommand: PC_DEFAULT_HOOK_COMMAND,
|
|
2808
|
-
statusMessage: "Checking pc handoff"
|
|
2809
|
-
};
|
|
2810
|
-
var isJsonRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2811
|
-
var readJsonRecord = (filePath) => {
|
|
2812
|
-
if (!existsSync5(filePath)) {
|
|
2813
|
-
return {};
|
|
2814
|
-
}
|
|
2815
|
-
const parsed = JSON.parse(readFileSync10(filePath, "utf-8"));
|
|
2816
|
-
if (!isJsonRecord2(parsed)) {
|
|
2817
|
-
throw new Error("hooks.json must contain a JSON object");
|
|
2818
|
-
}
|
|
2819
|
-
return parsed;
|
|
2820
|
-
};
|
|
2821
|
-
var writeJsonRecord = (filePath, value) => {
|
|
2822
|
-
mkdirSync7(dirname9(filePath), { recursive: true });
|
|
2823
|
-
writeFileSync7(filePath, JSON.stringify(value, null, 2) + "\n", "utf-8");
|
|
2824
|
-
};
|
|
2825
|
-
var getOrCreateRecord = (record, key) => {
|
|
2826
|
-
const existing = record[key];
|
|
2827
|
-
if (isJsonRecord2(existing)) {
|
|
2828
|
-
return existing;
|
|
2829
|
-
}
|
|
2830
|
-
const next = {};
|
|
2831
|
-
record[key] = next;
|
|
2832
|
-
return next;
|
|
2833
|
-
};
|
|
2834
|
-
var getArray = (record, key) => {
|
|
2835
|
-
const existing = record[key];
|
|
2836
|
-
return Array.isArray(existing) ? existing : [];
|
|
2837
|
-
};
|
|
2838
|
-
var handlerMatchesDefinition = (definition) => (handler) => isJsonRecord2(handler) && typeof handler.command === "string" && [definition.commandMarker, ...definition.legacyCommandMarkers].some((marker) => handler.command.includes(marker));
|
|
2839
|
-
var handlerMatchesCommand = (handler, command) => isJsonRecord2(handler) && handler.command === command;
|
|
2840
|
-
var groupHasDefinitionHook = (definition) => (group) => isJsonRecord2(group) && getArray(group, "hooks").some(handlerMatchesDefinition(definition));
|
|
2841
|
-
var groupHasCurrentDefinitionHook = (group, command) => isJsonRecord2(group) && getArray(group, "hooks").some((handler) => handlerMatchesCommand(handler, command));
|
|
2842
|
-
var countDefinitionHandlers = (groups, definition) => groups.reduce((count, group) => {
|
|
2843
|
-
if (!isJsonRecord2(group)) {
|
|
2844
|
-
return count;
|
|
2845
|
-
}
|
|
2846
|
-
return count + getArray(group, "hooks").filter(handlerMatchesDefinition(definition)).length;
|
|
2847
|
-
}, 0);
|
|
2848
|
-
var configHasDefinitionHook = (config, definition) => {
|
|
2849
|
-
const hooks = config.hooks;
|
|
2850
|
-
if (!isJsonRecord2(hooks)) {
|
|
2851
|
-
return false;
|
|
2852
|
-
}
|
|
2853
|
-
return getArray(hooks, POST_TOOL_USE_EVENT).some(groupHasDefinitionHook(definition));
|
|
2854
|
-
};
|
|
2855
|
-
var configHasOnlyCurrentDefinitionHook = (config, definition, command) => {
|
|
2856
|
-
const hooks = config.hooks;
|
|
2857
|
-
if (!isJsonRecord2(hooks)) {
|
|
2858
|
-
return false;
|
|
2859
|
-
}
|
|
2860
|
-
const hasLegacy = getArray(hooks, PRE_TOOL_USE_EVENT).some(groupHasDefinitionHook(definition));
|
|
2861
|
-
const postGroups = getArray(hooks, POST_TOOL_USE_EVENT);
|
|
2862
|
-
const hasCurrent = postGroups.some((group) => groupHasCurrentDefinitionHook(group, command));
|
|
2863
|
-
return hasCurrent && !hasLegacy && countDefinitionHandlers(postGroups, definition) === 1;
|
|
2864
|
-
};
|
|
2865
|
-
var removeDefinitionHooksFromEvent = (hooks, eventName, definition) => {
|
|
2866
|
-
const previousGroups = getArray(hooks, eventName);
|
|
2867
|
-
let removed = false;
|
|
2868
|
-
const nextGroups = previousGroups.map((group) => {
|
|
2869
|
-
if (!isJsonRecord2(group)) {
|
|
2870
|
-
return group;
|
|
2871
|
-
}
|
|
2872
|
-
const previousHandlers = getArray(group, "hooks");
|
|
2873
|
-
const nextHandlers = previousHandlers.filter((handler) => {
|
|
2874
|
-
const matches = handlerMatchesDefinition(definition)(handler);
|
|
2875
|
-
if (matches) {
|
|
2876
|
-
removed = true;
|
|
2877
|
-
}
|
|
2878
|
-
return !matches;
|
|
2879
|
-
});
|
|
2880
|
-
if (nextHandlers.length === 0) {
|
|
2881
|
-
return null;
|
|
2882
|
-
}
|
|
2883
|
-
return {
|
|
2884
|
-
...group,
|
|
2885
|
-
hooks: nextHandlers
|
|
2886
|
-
};
|
|
2887
|
-
}).filter((group) => group !== null);
|
|
2888
|
-
if (!removed) {
|
|
2889
|
-
return false;
|
|
2890
|
-
}
|
|
2891
|
-
if (nextGroups.length > 0) {
|
|
2892
|
-
hooks[eventName] = nextGroups;
|
|
2893
|
-
} else {
|
|
2894
|
-
delete hooks[eventName];
|
|
2895
|
-
}
|
|
2896
|
-
return true;
|
|
2897
|
-
};
|
|
2898
|
-
var resolveCodexHooksPath = (codexHomePath) => join12(codexHomePath, "hooks.json");
|
|
2899
|
-
var buildCodexHookCommand = (params) => {
|
|
2900
|
-
const command = params.overrideCommand?.trim() ?? params.definition.defaultCommand;
|
|
2901
|
-
if (!command.includes(params.definition.commandMarker)) {
|
|
2902
|
-
throw new Error(`${params.definition.id} hook command must include: ${params.definition.commandMarker}`);
|
|
2903
|
-
}
|
|
2904
|
-
return command;
|
|
2905
|
-
};
|
|
2906
|
-
var buildContextPromotionHookCommand = (overrideCommand) => buildCodexHookCommand({
|
|
2907
|
-
definition: CONTEXT_PROMOTION_CODEX_HOOK,
|
|
2908
|
-
overrideCommand
|
|
2909
|
-
});
|
|
2910
|
-
var inspectCodexHook = (params) => ({
|
|
2911
|
-
hooksPath: params.hooksPath,
|
|
2912
|
-
installed: configHasDefinitionHook(readJsonRecord(params.hooksPath), params.definition)
|
|
2913
|
-
});
|
|
2914
|
-
var inspectContextPromotionHook = (hooksPath) => ({
|
|
2915
|
-
hooksPath,
|
|
2916
|
-
installed: inspectCodexHook({ hooksPath, definition: CONTEXT_PROMOTION_CODEX_HOOK }).installed
|
|
2917
|
-
});
|
|
2918
|
-
var installCodexHook = (params) => {
|
|
2919
|
-
const config = readJsonRecord(params.hooksPath);
|
|
2920
|
-
if (configHasOnlyCurrentDefinitionHook(config, params.definition, params.command)) {
|
|
2921
|
-
return {
|
|
2922
|
-
hooksPath: params.hooksPath,
|
|
2923
|
-
installed: true,
|
|
2924
|
-
changed: false
|
|
2925
|
-
};
|
|
2926
|
-
}
|
|
2927
|
-
const hooks = getOrCreateRecord(config, "hooks");
|
|
2928
|
-
removeDefinitionHooksFromEvent(hooks, PRE_TOOL_USE_EVENT, params.definition);
|
|
2929
|
-
removeDefinitionHooksFromEvent(hooks, POST_TOOL_USE_EVENT, params.definition);
|
|
2930
|
-
const existingGroups = getArray(hooks, POST_TOOL_USE_EVENT);
|
|
2931
|
-
const nextGroup = {
|
|
2932
|
-
matcher: BASH_MATCHER,
|
|
2933
|
-
hooks: [
|
|
2934
|
-
{
|
|
2935
|
-
type: "command",
|
|
2936
|
-
command: params.command,
|
|
2937
|
-
timeout: 30,
|
|
2938
|
-
statusMessage: params.definition.statusMessage
|
|
2939
|
-
}
|
|
2940
|
-
]
|
|
2941
|
-
};
|
|
2942
|
-
hooks[POST_TOOL_USE_EVENT] = [...existingGroups, nextGroup];
|
|
2943
|
-
writeJsonRecord(params.hooksPath, config);
|
|
2944
|
-
return {
|
|
2945
|
-
hooksPath: params.hooksPath,
|
|
2946
|
-
installed: true,
|
|
2947
|
-
changed: true
|
|
2948
|
-
};
|
|
2949
|
-
};
|
|
2950
|
-
var installContextPromotionHook = (params) => installCodexHook({
|
|
2951
|
-
hooksPath: params.hooksPath,
|
|
2952
|
-
definition: CONTEXT_PROMOTION_CODEX_HOOK,
|
|
2953
|
-
command: params.command
|
|
2954
|
-
});
|
|
2955
|
-
var uninstallCodexHook = (params) => {
|
|
2956
|
-
const config = readJsonRecord(params.hooksPath);
|
|
2957
|
-
const hooks = config.hooks;
|
|
2958
|
-
if (!isJsonRecord2(hooks)) {
|
|
2959
|
-
return { hooksPath: params.hooksPath, removed: false, changed: false };
|
|
2960
|
-
}
|
|
2961
|
-
const removedLegacy = removeDefinitionHooksFromEvent(hooks, PRE_TOOL_USE_EVENT, params.definition);
|
|
2962
|
-
const removedCurrent = removeDefinitionHooksFromEvent(hooks, POST_TOOL_USE_EVENT, params.definition);
|
|
2963
|
-
const removed = removedLegacy || removedCurrent;
|
|
2964
|
-
if (!removed) {
|
|
2965
|
-
return { hooksPath: params.hooksPath, removed: false, changed: false };
|
|
2966
|
-
}
|
|
2967
|
-
writeJsonRecord(params.hooksPath, config);
|
|
2968
|
-
return { hooksPath: params.hooksPath, removed: true, changed: true };
|
|
2969
|
-
};
|
|
2970
|
-
var uninstallContextPromotionHook = (hooksPath) => uninstallCodexHook({
|
|
2971
|
-
hooksPath,
|
|
2972
|
-
definition: CONTEXT_PROMOTION_CODEX_HOOK
|
|
2973
|
-
});
|
|
2974
|
-
|
|
2975
3830
|
// src/lib/paths.ts
|
|
2976
|
-
import { join as
|
|
2977
|
-
var resolveSkillsDir = () =>
|
|
2978
|
-
var resolveSubagentsDir = () =>
|
|
2979
|
-
var resolvePacksDir = () =>
|
|
2980
|
-
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");
|
|
2981
3836
|
var resolveBasePath = () => process.cwd();
|
|
2982
3837
|
var resolveUserBasePath = () => {
|
|
2983
3838
|
const userBasePath = process.env.AI_OPS_HOME ?? process.env.HOME;
|
|
@@ -3225,6 +4080,43 @@ ${result.notFound.map((file) => ` ${file}`).join("\n")}`);
|
|
|
3225
4080
|
p6.outro("ai-ops uninstall \uC644\uB8CC");
|
|
3226
4081
|
};
|
|
3227
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
|
+
|
|
3228
4120
|
// src/commands/skill.ts
|
|
3229
4121
|
import * as p7 from "@clack/prompts";
|
|
3230
4122
|
import { rmSync as rmSync5 } from "fs";
|
|
@@ -3261,17 +4153,17 @@ var findInstalledSkill = (installedSkills, skillId) => {
|
|
|
3261
4153
|
};
|
|
3262
4154
|
|
|
3263
4155
|
// src/lib/skill-install.ts
|
|
3264
|
-
import { existsSync as
|
|
3265
|
-
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";
|
|
3266
4158
|
var installSkillPackages = (basePath, packages) => {
|
|
3267
4159
|
const writtenRoots = [];
|
|
3268
4160
|
for (const skillPackage of packages) {
|
|
3269
|
-
const absRoot =
|
|
3270
|
-
if (
|
|
4161
|
+
const absRoot = resolve10(basePath, skillPackage.rootDir);
|
|
4162
|
+
if (existsSync7(absRoot)) {
|
|
3271
4163
|
rmSync4(absRoot, { recursive: true, force: true });
|
|
3272
4164
|
}
|
|
3273
4165
|
for (const file of skillPackage.files) {
|
|
3274
|
-
const absPath =
|
|
4166
|
+
const absPath = resolve10(basePath, file.relativePath);
|
|
3275
4167
|
mkdirSync8(dirname10(absPath), { recursive: true });
|
|
3276
4168
|
writeFileSync8(absPath, file.content + "\n", "utf-8");
|
|
3277
4169
|
}
|
|
@@ -3282,8 +4174,8 @@ var installSkillPackages = (basePath, packages) => {
|
|
|
3282
4174
|
var removeDirectories = (basePath, relativeDirs) => {
|
|
3283
4175
|
const removed = [];
|
|
3284
4176
|
for (const relativeDir of relativeDirs) {
|
|
3285
|
-
const absPath =
|
|
3286
|
-
if (!
|
|
4177
|
+
const absPath = resolve10(basePath, relativeDir);
|
|
4178
|
+
if (!existsSync7(absPath)) continue;
|
|
3287
4179
|
rmSync4(absPath, { recursive: true, force: true });
|
|
3288
4180
|
removed.push(relativeDir);
|
|
3289
4181
|
}
|
|
@@ -3462,14 +4354,14 @@ var skillUninstallCommand = async (skillId) => {
|
|
|
3462
4354
|
|
|
3463
4355
|
// src/commands/subagent.ts
|
|
3464
4356
|
import * as p8 from "@clack/prompts";
|
|
3465
|
-
import { existsSync as
|
|
4357
|
+
import { existsSync as existsSync9, rmSync as rmSync7 } from "fs";
|
|
3466
4358
|
|
|
3467
4359
|
// src/lib/subagent-install.ts
|
|
3468
|
-
import { existsSync as
|
|
3469
|
-
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";
|
|
3470
4362
|
var resolveInsideBasePath = (basePath, relativePath) => {
|
|
3471
|
-
const absBasePath =
|
|
3472
|
-
const absPath =
|
|
4363
|
+
const absBasePath = resolve11(basePath);
|
|
4364
|
+
const absPath = resolve11(absBasePath, relativePath);
|
|
3473
4365
|
const fromBase = relative3(absBasePath, absPath);
|
|
3474
4366
|
if (fromBase.length === 0 || fromBase.startsWith("..") || isAbsolute3(fromBase)) {
|
|
3475
4367
|
throw new Error(`Subagent path escapes AI_OPS_HOME: ${relativePath}`);
|
|
@@ -3481,7 +4373,7 @@ var installSubagentPackages = (basePath, packages) => {
|
|
|
3481
4373
|
for (const subagentPackage of packages) {
|
|
3482
4374
|
for (const file of subagentPackage.files) {
|
|
3483
4375
|
const absPath = resolveInsideBasePath(basePath, file.relativePath);
|
|
3484
|
-
if (
|
|
4376
|
+
if (existsSync8(absPath)) {
|
|
3485
4377
|
rmSync6(absPath, { recursive: true, force: true });
|
|
3486
4378
|
}
|
|
3487
4379
|
mkdirSync9(dirname11(absPath), { recursive: true });
|
|
@@ -3495,7 +4387,7 @@ var removeSubagentFiles = (basePath, relativePaths) => {
|
|
|
3495
4387
|
const removed = [];
|
|
3496
4388
|
for (const relativePath of relativePaths) {
|
|
3497
4389
|
const absPath = resolveInsideBasePath(basePath, relativePath);
|
|
3498
|
-
if (!
|
|
4390
|
+
if (!existsSync8(absPath)) continue;
|
|
3499
4391
|
rmSync6(absPath, { recursive: true, force: true });
|
|
3500
4392
|
removed.push(relativePath);
|
|
3501
4393
|
}
|
|
@@ -3557,7 +4449,7 @@ var writeUserSubagentState = (params) => {
|
|
|
3557
4449
|
};
|
|
3558
4450
|
var readInstalledSubagents = (basePath) => readSubagentManifest(resolveSubagentManifestPath(basePath))?.subagents ?? [];
|
|
3559
4451
|
var warnMissingSkills = (requiredSkills) => {
|
|
3560
|
-
const missing = requiredSkills.filter((skill) => !
|
|
4452
|
+
const missing = requiredSkills.filter((skill) => !existsSync9(skill.path));
|
|
3561
4453
|
if (missing.length === 0) {
|
|
3562
4454
|
return;
|
|
3563
4455
|
}
|
|
@@ -3868,13 +4760,13 @@ var parseMax = (max) => {
|
|
|
3868
4760
|
}
|
|
3869
4761
|
return parsed;
|
|
3870
4762
|
};
|
|
3871
|
-
var readStdin = async () => new Promise((
|
|
4763
|
+
var readStdin = async () => new Promise((resolve12, reject) => {
|
|
3872
4764
|
let raw = "";
|
|
3873
4765
|
process.stdin.setEncoding("utf-8");
|
|
3874
4766
|
process.stdin.on("data", (chunk) => {
|
|
3875
4767
|
raw += chunk;
|
|
3876
4768
|
});
|
|
3877
|
-
process.stdin.on("end", () =>
|
|
4769
|
+
process.stdin.on("end", () => resolve12(raw));
|
|
3878
4770
|
process.stdin.on("error", reject);
|
|
3879
4771
|
});
|
|
3880
4772
|
var reportContextPromotionError = (error) => {
|
|
@@ -3975,8 +4867,8 @@ var contextPromotionPostToolUseHookCommand = async () => {
|
|
|
3975
4867
|
|
|
3976
4868
|
// src/commands/codex-hook.ts
|
|
3977
4869
|
import * as p11 from "@clack/prompts";
|
|
3978
|
-
import { existsSync as
|
|
3979
|
-
import { join as
|
|
4870
|
+
import { existsSync as existsSync10 } from "fs";
|
|
4871
|
+
import { join as join16 } from "path";
|
|
3980
4872
|
var CONTEXT_PROMOTION_REVIEW_SKILL_ID = "context-promotion-review";
|
|
3981
4873
|
var resolveCodexHomePath = () => {
|
|
3982
4874
|
const codexHome = process.env.CODEX_HOME;
|
|
@@ -4014,7 +4906,7 @@ var resolveContextPromotionReviewSkill = () => {
|
|
|
4014
4906
|
};
|
|
4015
4907
|
var hasInstalledContextPromotionReviewSkill = (basePath) => {
|
|
4016
4908
|
const installedSkill = findInstalledSkill(readInstalledSkills2(basePath), CONTEXT_PROMOTION_REVIEW_SKILL_ID);
|
|
4017
|
-
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"));
|
|
4018
4910
|
};
|
|
4019
4911
|
var ensureContextPromotionReviewSkill = (basePath) => {
|
|
4020
4912
|
const skill = resolveContextPromotionReviewSkill();
|
|
@@ -4028,7 +4920,7 @@ var ensureContextPromotionReviewSkill = (basePath) => {
|
|
|
4028
4920
|
skill,
|
|
4029
4921
|
requestedTools
|
|
4030
4922
|
});
|
|
4031
|
-
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"));
|
|
4032
4924
|
if (alreadyInstalled) {
|
|
4033
4925
|
return { changed: false, installedSkill };
|
|
4034
4926
|
}
|
|
@@ -4091,8 +4983,8 @@ var codexHookUninstallCommand = async (hookId) => {
|
|
|
4091
4983
|
|
|
4092
4984
|
// src/commands/integration.ts
|
|
4093
4985
|
import * as p12 from "@clack/prompts";
|
|
4094
|
-
import { existsSync as
|
|
4095
|
-
import { join as
|
|
4986
|
+
import { existsSync as existsSync11, rmSync as rmSync8 } from "fs";
|
|
4987
|
+
import { join as join17 } from "path";
|
|
4096
4988
|
var CODEX_HOOK_DEFINITIONS = [CONTEXT_PROMOTION_CODEX_HOOK, PC_CODEX_HOOK];
|
|
4097
4989
|
var resolveCodexHomePath2 = () => {
|
|
4098
4990
|
const codexHome = process.env.CODEX_HOME;
|
|
@@ -4165,13 +5057,13 @@ var reportIntegrationError = (error) => {
|
|
|
4165
5057
|
p12.log.error(message);
|
|
4166
5058
|
process.exitCode = 1;
|
|
4167
5059
|
};
|
|
4168
|
-
var readStdin2 = async () => new Promise((
|
|
5060
|
+
var readStdin2 = async () => new Promise((resolve12, reject) => {
|
|
4169
5061
|
let raw = "";
|
|
4170
5062
|
process.stdin.setEncoding("utf-8");
|
|
4171
5063
|
process.stdin.on("data", (chunk) => {
|
|
4172
5064
|
raw += chunk;
|
|
4173
5065
|
});
|
|
4174
|
-
process.stdin.on("end", () =>
|
|
5066
|
+
process.stdin.on("end", () => resolve12(raw));
|
|
4175
5067
|
process.stdin.on("error", reject);
|
|
4176
5068
|
});
|
|
4177
5069
|
var readInstalledSkills3 = (basePath) => (readSkillRegistry(resolveSkillRegistryPath(basePath))?.skills ?? []).map((installedSkill) => ({
|
|
@@ -4187,7 +5079,7 @@ var resolveSkillById2 = (skillId) => {
|
|
|
4187
5079
|
};
|
|
4188
5080
|
var hasInstalledCodexSkill = (params) => {
|
|
4189
5081
|
const installedSkill = findInstalledSkill(readInstalledSkills3(params.basePath), params.skillId);
|
|
4190
|
-
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"));
|
|
4191
5083
|
};
|
|
4192
5084
|
var writeUserSkillState2 = (params) => {
|
|
4193
5085
|
const registryPath = resolveSkillRegistryPath(params.basePath);
|
|
@@ -4215,7 +5107,7 @@ var ensureSkillComponent = (params) => {
|
|
|
4215
5107
|
skill,
|
|
4216
5108
|
requestedTools
|
|
4217
5109
|
});
|
|
4218
|
-
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"));
|
|
4219
5111
|
if (alreadyCurrent) {
|
|
4220
5112
|
return {
|
|
4221
5113
|
type: INTEGRATION_COMPONENT_TYPE.SKILL,
|
|
@@ -4477,6 +5369,8 @@ program.command("update").description("project operating layer \uAC31\uC2E0").op
|
|
|
4477
5369
|
program.command("diff").description("project operating layer drift \uBE44\uAD50").action(() => diffCommand());
|
|
4478
5370
|
program.command("audit").description("project operating layer \uC0C1\uD0DC \uAC80\uC0AC").action(() => auditCommand());
|
|
4479
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));
|
|
4480
5374
|
var skillCommand = program.command("skill").description("\uC5D0\uC774\uC804\uD2B8 skill \uC124\uCE58/\uC870\uD68C/\uAC31\uC2E0");
|
|
4481
5375
|
var applySkillInstallOptions = (command) => command.option("--tool <tool...>", "\uB300\uC0C1 \uB3C4\uAD6C \uC9C0\uC815");
|
|
4482
5376
|
skillCommand.command("list").description("\uC0AC\uC6A9 \uAC00\uB2A5\uD55C skill \uBAA9\uB85D").action(() => skillListCommand());
|