dsh-industry-research 0.1.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.
Files changed (99) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/LICENSE +201 -0
  3. package/README.es.md +175 -0
  4. package/README.hi.md +175 -0
  5. package/README.md +175 -0
  6. package/README.pt.md +175 -0
  7. package/README.zh.md +175 -0
  8. package/THIRD_PARTY_NOTICES.md +21 -0
  9. package/cordis.patch.yml +44 -0
  10. package/lib/index.js +2080 -0
  11. package/lib/types/chain.d.ts +68 -0
  12. package/lib/types/chain.d.ts.map +1 -0
  13. package/lib/types/chain.js +88 -0
  14. package/lib/types/chain.js.map +1 -0
  15. package/lib/types/company.d.ts +121 -0
  16. package/lib/types/company.d.ts.map +1 -0
  17. package/lib/types/company.js +170 -0
  18. package/lib/types/company.js.map +1 -0
  19. package/lib/types/config.d.ts +72 -0
  20. package/lib/types/config.d.ts.map +1 -0
  21. package/lib/types/config.js +86 -0
  22. package/lib/types/config.js.map +1 -0
  23. package/lib/types/engine-bridge.d.ts +68 -0
  24. package/lib/types/engine-bridge.d.ts.map +1 -0
  25. package/lib/types/engine-bridge.js +18 -0
  26. package/lib/types/engine-bridge.js.map +1 -0
  27. package/lib/types/events.d.ts +79 -0
  28. package/lib/types/events.d.ts.map +1 -0
  29. package/lib/types/events.js +13 -0
  30. package/lib/types/events.js.map +1 -0
  31. package/lib/types/index.d.ts +58 -0
  32. package/lib/types/index.d.ts.map +1 -0
  33. package/lib/types/index.js +111 -0
  34. package/lib/types/index.js.map +1 -0
  35. package/lib/types/paths.d.ts +45 -0
  36. package/lib/types/paths.d.ts.map +1 -0
  37. package/lib/types/paths.js +93 -0
  38. package/lib/types/paths.js.map +1 -0
  39. package/lib/types/report.d.ts +134 -0
  40. package/lib/types/report.d.ts.map +1 -0
  41. package/lib/types/report.js +278 -0
  42. package/lib/types/report.js.map +1 -0
  43. package/lib/types/sources.d.ts +55 -0
  44. package/lib/types/sources.d.ts.map +1 -0
  45. package/lib/types/sources.js +73 -0
  46. package/lib/types/sources.js.map +1 -0
  47. package/lib/types/timeline.d.ts +78 -0
  48. package/lib/types/timeline.d.ts.map +1 -0
  49. package/lib/types/timeline.js +129 -0
  50. package/lib/types/timeline.js.map +1 -0
  51. package/lib/types/toolkit.d.ts +61 -0
  52. package/lib/types/toolkit.d.ts.map +1 -0
  53. package/lib/types/toolkit.js +77 -0
  54. package/lib/types/toolkit.js.map +1 -0
  55. package/lib/types/tools/company.d.ts +36 -0
  56. package/lib/types/tools/company.d.ts.map +1 -0
  57. package/lib/types/tools/company.js +139 -0
  58. package/lib/types/tools/company.js.map +1 -0
  59. package/lib/types/tools/map.d.ts +44 -0
  60. package/lib/types/tools/map.d.ts.map +1 -0
  61. package/lib/types/tools/map.js +211 -0
  62. package/lib/types/tools/map.js.map +1 -0
  63. package/lib/types/tools/report.d.ts +61 -0
  64. package/lib/types/tools/report.d.ts.map +1 -0
  65. package/lib/types/tools/report.js +277 -0
  66. package/lib/types/tools/report.js.map +1 -0
  67. package/lib/types/tools/track.d.ts +46 -0
  68. package/lib/types/tools/track.d.ts.map +1 -0
  69. package/lib/types/tools/track.js +188 -0
  70. package/lib/types/tools/track.js.map +1 -0
  71. package/lib/types/version.d.ts +8 -0
  72. package/lib/types/version.d.ts.map +1 -0
  73. package/lib/types/version.js +8 -0
  74. package/lib/types/version.js.map +1 -0
  75. package/lib/types/web.d.ts +74 -0
  76. package/lib/types/web.d.ts.map +1 -0
  77. package/lib/types/web.js +60 -0
  78. package/lib/types/web.js.map +1 -0
  79. package/package.json +143 -0
  80. package/skills/company-research-method/SKILL.md +50 -0
  81. package/skills/industry-research-method/SKILL.md +57 -0
  82. package/skills/industry-research-method/references/frameworks.md +42 -0
  83. package/src/chain.ts +132 -0
  84. package/src/company.ts +238 -0
  85. package/src/config.ts +154 -0
  86. package/src/engine-bridge.ts +62 -0
  87. package/src/events.ts +82 -0
  88. package/src/index.ts +139 -0
  89. package/src/paths.ts +96 -0
  90. package/src/report.ts +326 -0
  91. package/src/sources.ts +95 -0
  92. package/src/timeline.ts +155 -0
  93. package/src/toolkit.ts +87 -0
  94. package/src/tools/company.ts +157 -0
  95. package/src/tools/map.ts +241 -0
  96. package/src/tools/report.ts +304 -0
  97. package/src/tools/track.ts +223 -0
  98. package/src/version.ts +8 -0
  99. package/src/web.ts +94 -0
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Optional bridge to the `ctx.researchReport` report engine, provided by the
3
+ * sibling `dsh-research-report` plugin. The engine is never injected and never
4
+ * imported: it is looked up structurally with `ctx.get('researchReport')`, and
5
+ * `industry_report` falls back to the builtin Markdown renderer when the
6
+ * engine is absent. The request/result types below are the frozen
7
+ * cross-plugin contract and must stay byte-identical with it.
8
+ * @module dsh-industry-research/engine-bridge
9
+ */
10
+ import type { Context } from '@deepseek-ai/cordis';
11
+ export interface ReportSectionInput {
12
+ heading: string;
13
+ /** Paragraphs; each claim string may carry citations. */
14
+ paragraphs: Array<{
15
+ text: string;
16
+ claimIds?: string[];
17
+ }>;
18
+ }
19
+ export interface EvidenceInput {
20
+ id: string;
21
+ title: string;
22
+ /** Where the evidence came from (URL or workspace path). */
23
+ origin: string;
24
+ /** Verbatim content snapshot used for byte-level checks. */
25
+ content: string;
26
+ /** ISO-8601 time the snapshot was captured. */
27
+ capturedAt: string;
28
+ }
29
+ export interface AssembleReportRequest {
30
+ title: string;
31
+ topic: string;
32
+ evidence: EvidenceInput[];
33
+ sections: ReportSectionInput[];
34
+ /** Every claim id referenced in sections must be registered here. */
35
+ claims: Array<{
36
+ id: string;
37
+ text: string;
38
+ evidenceIds: string[];
39
+ }>;
40
+ }
41
+ export interface AssembleReportResult {
42
+ /** Workspace path of the sealed report directory (report.md + manifest.json). */
43
+ reportDir: string;
44
+ /** SHA-256 content hash of manifest.json. */
45
+ sealHash: string;
46
+ /** Per-claim verification verdicts. */
47
+ verdicts: Array<{
48
+ claimId: string;
49
+ status: 'verified' | 'unverified' | 'contradicted';
50
+ note?: string;
51
+ }>;
52
+ }
53
+ /** The structural surface of the optional `ctx.researchReport` engine. */
54
+ export interface ResearchReportLike {
55
+ /**
56
+ * Assemble and seal a report from evidence, sections, and claims.
57
+ * @param request - the frozen assemble request.
58
+ * @returns the sealed report directory, manifest hash, and per-claim verdicts.
59
+ */
60
+ assemble(request: AssembleReportRequest): Promise<AssembleReportResult>;
61
+ }
62
+ /**
63
+ * Look up the optional report engine.
64
+ * @param ctx - the plugin context.
65
+ * @returns the engine surface, or undefined when no engine is mounted.
66
+ */
67
+ export declare function lookupEngine(ctx: Context): ResearchReportLike | undefined;
68
+ //# sourceMappingURL=engine-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-bridge.d.ts","sourceRoot":"","sources":["../../src/engine-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAA;IACf,yDAAyD;IACzD,UAAU,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAA;CACzD;AACD,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,4DAA4D;IAC5D,MAAM,EAAE,MAAM,CAAA;IACd,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAA;IACf,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAA;CACnB;AACD,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,QAAQ,EAAE,kBAAkB,EAAE,CAAA;IAC9B,qEAAqE;IACrE,MAAM,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAA;CACnE;AACD,MAAM,WAAW,oBAAoB;IACnC,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAA;IACjB,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAA;IAChB,uCAAuC;IACvC,QAAQ,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,UAAU,GAAG,YAAY,GAAG,cAAc,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACxG;AAED,0EAA0E;AAC1E,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAA;CACxE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,kBAAkB,GAAG,SAAS,CAEzE"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Optional bridge to the `ctx.researchReport` report engine, provided by the
3
+ * sibling `dsh-research-report` plugin. The engine is never injected and never
4
+ * imported: it is looked up structurally with `ctx.get('researchReport')`, and
5
+ * `industry_report` falls back to the builtin Markdown renderer when the
6
+ * engine is absent. The request/result types below are the frozen
7
+ * cross-plugin contract and must stay byte-identical with it.
8
+ * @module dsh-industry-research/engine-bridge
9
+ */
10
+ /**
11
+ * Look up the optional report engine.
12
+ * @param ctx - the plugin context.
13
+ * @returns the engine surface, or undefined when no engine is mounted.
14
+ */
15
+ export function lookupEngine(ctx) {
16
+ return ctx.get('researchReport');
17
+ }
18
+ //# sourceMappingURL=engine-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-bridge.js","sourceRoot":"","sources":["../../src/engine-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA8CH;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,OAAO,GAAG,CAAC,GAAG,CAAC,gBAAgB,CAA8C,CAAA;AAC/E,CAAC"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Typed Cordis events emitted after a tool commits its artifacts. These are
3
+ * live observability events (other plugins may listen); they are NOT appended
4
+ * to the session log. The rc.6 `Session.append` signature has no `ignorable`
5
+ * marker for out-of-repo event types and there is no external
6
+ * event-registration surface, so appending `industry-research/*` session
7
+ * events would make the persistence coordinator refuse the log on restore —
8
+ * the durable record is the workspace artifacts themselves, and model-visible
9
+ * tool results ride the durable `tool/result` session event.
10
+ * @module dsh-industry-research/events
11
+ */
12
+ /** Payload of `industry-research/map`. */
13
+ export interface MapEventPayload {
14
+ /** Industry display name. */
15
+ industry: string;
16
+ /** Absolute path of the written `chain.json`. */
17
+ path: string;
18
+ /** Node count of the committed map. */
19
+ nodes: number;
20
+ /** Edge count of the committed map. */
21
+ edges: number;
22
+ /** Declared gap count of the committed map. */
23
+ gaps: number;
24
+ }
25
+ /** Payload of `industry-research/track`. */
26
+ export interface TrackEventPayload {
27
+ /** Industry display name. */
28
+ industry: string;
29
+ /** Absolute path of the `timeline.jsonl`. */
30
+ path: string;
31
+ /** Entries appended by this call. */
32
+ added: number;
33
+ /** Batch entries dropped as duplicates. */
34
+ duplicates: number;
35
+ /** Total entries retained after the merge. */
36
+ total: number;
37
+ }
38
+ /** Payload of `industry-research/report`. */
39
+ export interface ReportEventPayload {
40
+ /** Industry display name. */
41
+ industry: string;
42
+ /** Which engine produced the report. */
43
+ engine: 'research-report' | 'builtin-fallback';
44
+ /** Absolute report directory. */
45
+ reportDir: string;
46
+ /** Claim count of the report. */
47
+ claims: number;
48
+ /** Evidence count of the report. */
49
+ evidence: number;
50
+ }
51
+ declare module '@deepseek-ai/cordis' {
52
+ interface Events {
53
+ /**
54
+ * An `industry_map` call committed a validated chain map to the
55
+ * workspace. Fire-and-forget observability; listener failures are
56
+ * contained by the dispatcher.
57
+ * @mode emit
58
+ * @param payload - the committed map summary (paths and counts).
59
+ */
60
+ 'industry-research/map'(payload: MapEventPayload): void;
61
+ /**
62
+ * An `industry_track` call merged new entries into an industry timeline.
63
+ * Fire-and-forget observability; listener failures are contained by the
64
+ * dispatcher.
65
+ * @mode emit
66
+ * @param payload - the merge summary (paths and counts).
67
+ */
68
+ 'industry-research/track'(payload: TrackEventPayload): void;
69
+ /**
70
+ * An `industry_report` call produced a report (engine-sealed or
71
+ * builtin-fallback). Fire-and-forget observability; listener failures
72
+ * are contained by the dispatcher.
73
+ * @mode emit
74
+ * @param payload - the report summary (engine, directory, counts).
75
+ */
76
+ 'industry-research/report'(payload: ReportEventPayload): void;
77
+ }
78
+ }
79
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,0CAA0C;AAC1C,MAAM,WAAW,eAAe;IAC9B,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAA;IACZ,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAA;IACb,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAA;IACb,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAA;CACb;AAED,4CAA4C;AAC5C,MAAM,WAAW,iBAAiB;IAChC,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAA;IACZ,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAA;IACb,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAA;IAClB,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAA;CACd;AAED,6CAA6C;AAC7C,MAAM,WAAW,kBAAkB;IACjC,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,wCAAwC;IACxC,MAAM,EAAE,iBAAiB,GAAG,kBAAkB,CAAA;IAC9C,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,MAAM;QACd;;;;;;WAMG;QACH,uBAAuB,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAAA;QACvD;;;;;;WAMG;QACH,yBAAyB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAAA;QAC3D;;;;;;WAMG;QACH,0BAA0B,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAAA;KAC9D;CACF"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Typed Cordis events emitted after a tool commits its artifacts. These are
3
+ * live observability events (other plugins may listen); they are NOT appended
4
+ * to the session log. The rc.6 `Session.append` signature has no `ignorable`
5
+ * marker for out-of-repo event types and there is no external
6
+ * event-registration surface, so appending `industry-research/*` session
7
+ * events would make the persistence coordinator refuse the log on restore —
8
+ * the durable record is the workspace artifacts themselves, and model-visible
9
+ * tool results ride the durable `tool/result` session event.
10
+ * @module dsh-industry-research/events
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * `dsh-industry-research` — industry and company research domain pack for
3
+ * DeepSeek Harness. Mounts four workspace-bound research tools
4
+ * (`industry_map` / `industry_track` / `company_scan` / `industry_report`),
5
+ * publishes two methodology skills (`industry-research-method`,
6
+ * `company-research-method`) from the packaged `skills/` directory, and emits
7
+ * typed Cordis events after each committed artifact. The web capability
8
+ * (`ctx.web`) and the report engine (`ctx.researchReport`) are optional and
9
+ * looked up structurally at execution time — never injected. Research only;
10
+ * not investment advice.
11
+ *
12
+ * Function plugin — no default export (the Loader unwraps
13
+ * `exports.default ?? exports`, and a stray default would discard
14
+ * `name`/`inject`/`Config`/`apply`).
15
+ * @module dsh-industry-research
16
+ */
17
+ import type { Context } from '@deepseek-ai/cordis';
18
+ import { Config } from './config.js';
19
+ export declare const name = "industry-research";
20
+ /** The four tools and the skill provider; web/engine stay optional lookups. */
21
+ export declare const inject: string[];
22
+ export { Config, resolveConfig } from './config.js';
23
+ export type { Config as IndustryResearchConfig, ResolvedConfig } from './config.js';
24
+ export { VERSION } from './version.js';
25
+ export { CHAIN_TIERS, chainGaps, validateChainMap } from './chain.js';
26
+ export type { ChainEdge, ChainMap, ChainMetric, ChainNode, ChainTier } from './chain.js';
27
+ export { loadSources, registerSource, saveSources, sha256Of } from './sources.js';
28
+ export type { SourceEntry, SourceRegistry } from './sources.js';
29
+ export { mergeTimeline, normalizeUrl, readTimeline, sourceAllowed } from './timeline.js';
30
+ export type { TimelineEntry, TimelineMerge } from './timeline.js';
31
+ export { boundFigures, readCard, renderCardMarkdown, scanFile, writeCard, DISCLAIMER, READABLE_EXTENSIONS } from './company.js';
32
+ export type { CardSource, CardWebSource, CompanyCard, FigureCandidate, FileOutline, ScannedFile } from './company.js';
33
+ export { autoDraft, AUTO_SECTIONS, buildEvidence, renderFallbackMarkdown, reportDirName, validateDraft, writeFallbackReport } from './report.js';
34
+ export type { AutoSection, FallbackManifest, LoadedArtifacts, ReportClaim, ReportDraft } from './report.js';
35
+ export { lookupEngine } from './engine-bridge.js';
36
+ export type { AssembleReportRequest, AssembleReportResult, EvidenceInput, ReportSectionInput, ResearchReportLike, } from './engine-bridge.js';
37
+ export { lookupWeb, requestSignal, requireWeb, webErrorMessage } from './web.js';
38
+ export type { WebFetchOutcome, WebLike, WebSearchOutcome, WebSource } from './web.js';
39
+ export { resolveContained, resolveIndustryRoot, resolveWorkspaceFile, safeSegment } from './paths.js';
40
+ export { chainPathOf, companyDirOf, industryDirOf, notesDirOf, reportsDirOf, sourcesPathOf, timelinePathOf, workspaceOf } from './toolkit.js';
41
+ export type { MapEventPayload, ReportEventPayload, TrackEventPayload } from './events.js';
42
+ export { buildIndustryMapTool } from './tools/map.js';
43
+ export type { IndustryMapValue } from './tools/map.js';
44
+ export { buildIndustryTrackTool } from './tools/track.js';
45
+ export type { IndustryTrackValue } from './tools/track.js';
46
+ export { buildCompanyScanTool } from './tools/company.js';
47
+ export type { CompanyScanValue } from './tools/company.js';
48
+ export { buildIndustryReportTool, loadArtifacts } from './tools/report.js';
49
+ export type { IndustryReportValue } from './tools/report.js';
50
+ /**
51
+ * Mount the research pack: validate config (fail loud), publish the packaged
52
+ * skills, and register the four tools. With `enabled: false` nothing is
53
+ * registered and the plugin stays inert.
54
+ * @param ctx - the plugin context (host).
55
+ * @param config - raw plugin config.
56
+ */
57
+ export declare function apply(ctx: Context, config?: Config): void;
58
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * `dsh-industry-research` — industry and company research domain pack for
3
+ * DeepSeek Harness. Mounts four workspace-bound research tools
4
+ * (`industry_map` / `industry_track` / `company_scan` / `industry_report`),
5
+ * publishes two methodology skills (`industry-research-method`,
6
+ * `company-research-method`) from the packaged `skills/` directory, and emits
7
+ * typed Cordis events after each committed artifact. The web capability
8
+ * (`ctx.web`) and the report engine (`ctx.researchReport`) are optional and
9
+ * looked up structurally at execution time — never injected. Research only;
10
+ * not investment advice.
11
+ *
12
+ * Function plugin — no default export (the Loader unwraps
13
+ * `exports.default ?? exports`, and a stray default would discard
14
+ * `name`/`inject`/`Config`/`apply`).
15
+ * @module dsh-industry-research
16
+ */
17
+ import { existsSync, readdirSync } from 'node:fs';
18
+ import { dirname, join, resolve } from 'node:path';
19
+ import { fileURLToPath } from 'node:url';
20
+ import { FileSystemSkillProvider } from '@deepseek-ai/dsh-skill-filesystem';
21
+ import { resolveConfig } from "./config.js";
22
+ import { buildIndustryMapTool } from "./tools/map.js";
23
+ import { buildIndustryTrackTool } from "./tools/track.js";
24
+ import { buildCompanyScanTool } from "./tools/company.js";
25
+ import { buildIndustryReportTool } from "./tools/report.js";
26
+ import { VERSION } from "./version.js";
27
+ export const name = 'industry-research';
28
+ /** The four tools and the skill provider; web/engine stay optional lookups. */
29
+ export const inject = ['skills', 'tools'];
30
+ export { Config, resolveConfig } from "./config.js";
31
+ export { VERSION } from "./version.js";
32
+ export { CHAIN_TIERS, chainGaps, validateChainMap } from "./chain.js";
33
+ export { loadSources, registerSource, saveSources, sha256Of } from "./sources.js";
34
+ export { mergeTimeline, normalizeUrl, readTimeline, sourceAllowed } from "./timeline.js";
35
+ export { boundFigures, readCard, renderCardMarkdown, scanFile, writeCard, DISCLAIMER, READABLE_EXTENSIONS } from "./company.js";
36
+ export { autoDraft, AUTO_SECTIONS, buildEvidence, renderFallbackMarkdown, reportDirName, validateDraft, writeFallbackReport } from "./report.js";
37
+ export { lookupEngine } from "./engine-bridge.js";
38
+ export { lookupWeb, requestSignal, requireWeb, webErrorMessage } from "./web.js";
39
+ export { resolveContained, resolveIndustryRoot, resolveWorkspaceFile, safeSegment } from "./paths.js";
40
+ export { chainPathOf, companyDirOf, industryDirOf, notesDirOf, reportsDirOf, sourcesPathOf, timelinePathOf, workspaceOf } from "./toolkit.js";
41
+ export { buildIndustryMapTool } from "./tools/map.js";
42
+ export { buildIndustryTrackTool } from "./tools/track.js";
43
+ export { buildCompanyScanTool } from "./tools/company.js";
44
+ export { buildIndustryReportTool, loadArtifacts } from "./tools/report.js";
45
+ /** Directory of this module: `src/` under tsx/vitest or `lib/` when built. */
46
+ const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
47
+ /** Whether a directory contains at least one `<skill>/SKILL.md` bundle. */
48
+ function hasSkillBundles(dir) {
49
+ if (!existsSync(dir))
50
+ return false;
51
+ let entries;
52
+ try {
53
+ entries = readdirSync(dir, { withFileTypes: true });
54
+ }
55
+ catch {
56
+ return false;
57
+ }
58
+ return entries.some(entry => entry.isDirectory() && existsSync(join(dir, entry.name, 'SKILL.md')));
59
+ }
60
+ /**
61
+ * Resolve the skills root to publish and fail loud on misconfiguration: an
62
+ * explicit `skillsDir` must exist and hold bundles, and the packaged default
63
+ * (`skills/` beside `src/` or `lib/`) must exist — never mount silently with
64
+ * zero skills.
65
+ * @param skillsDir - explicit config override, if any.
66
+ * @returns the validated skills root.
67
+ */
68
+ function resolveSkillsRoot(skillsDir) {
69
+ if (skillsDir !== undefined) {
70
+ const root = resolve(skillsDir);
71
+ if (!hasSkillBundles(root)) {
72
+ throw new Error(`industry-research: config.skillsDir "${skillsDir}" does not exist or contains no <skill>/SKILL.md bundles`);
73
+ }
74
+ return root;
75
+ }
76
+ const root = join(MODULE_DIR, '..', 'skills');
77
+ if (!hasSkillBundles(root)) {
78
+ throw new Error(`industry-research: packaged skills root ${root} is missing; expected skills/<name>/SKILL.md bundles beside the built lib/. Set config.skillsDir to an explicit root.`);
79
+ }
80
+ return root;
81
+ }
82
+ /**
83
+ * Mount the research pack: validate config (fail loud), publish the packaged
84
+ * skills, and register the four tools. With `enabled: false` nothing is
85
+ * registered and the plugin stays inert.
86
+ * @param ctx - the plugin context (host).
87
+ * @param config - raw plugin config.
88
+ */
89
+ export function apply(ctx, config = {}) {
90
+ const resolved = resolveConfig(config);
91
+ const logger = ctx.logger('industry-research');
92
+ if (!resolved.enabled) {
93
+ logger.info('disabled: enabled is false — no research capabilities are mounted');
94
+ return;
95
+ }
96
+ const skillsRoot = resolveSkillsRoot(resolved.skillsDir);
97
+ ctx.effect(function* () {
98
+ yield ctx.skills.registerProvider(control => new FileSystemSkillProvider(ctx, control, {
99
+ providerName: 'industry-research',
100
+ includeDefaultRoots: false,
101
+ customSkillDirs: [skillsRoot],
102
+ watch: false,
103
+ }));
104
+ });
105
+ ctx.tools.register(buildIndustryMapTool(ctx, resolved));
106
+ ctx.tools.register(buildIndustryTrackTool(ctx, resolved));
107
+ ctx.tools.register(buildCompanyScanTool(ctx, resolved));
108
+ ctx.tools.register(buildIndustryReportTool(ctx, resolved));
109
+ logger.info(`industry-research ${VERSION} mounted: 4 tools, skills from ${skillsRoot}`);
110
+ }
111
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Workspace path resolution and containment for `dsh-industry-research`. All
3
+ * artifacts live under `<cwd>/<industryRoot>/`; every name crossing a tool
4
+ * argument boundary (industry, company, data file) is validated so a crafted
5
+ * value cannot escape the workspace. Both sides of every containment check
6
+ * are resolved before comparison (`path.resolve` returns backslashes on
7
+ * Windows, and comparing against a forward-slash input would always fail).
8
+ * @module dsh-industry-research/paths
9
+ */
10
+ /**
11
+ * Validate one path segment (an industry or company directory name). CJK and
12
+ * other Unicode letters are fine; separators, traversal, control characters,
13
+ * leading/trailing dots/spaces, and Windows device names are rejected.
14
+ * @param label - what the segment names (for the error message).
15
+ * @param value - the raw user/model-supplied name.
16
+ * @returns the trimmed, validated segment.
17
+ */
18
+ export declare function safeSegment(label: string, value: string): string;
19
+ /**
20
+ * Resolve `root` against the workspace cwd and return the absolute root.
21
+ * A relative `industryRoot` is workspace-relative; an absolute one is used
22
+ * as-is (deployment choice).
23
+ * @param cwd - absolute session workspace root.
24
+ * @param industryRoot - configured root (relative or absolute).
25
+ * @returns the absolute industry root.
26
+ */
27
+ export declare function resolveIndustryRoot(cwd: string, industryRoot: string): string;
28
+ /**
29
+ * Resolve a user-supplied workspace-relative file path and verify containment
30
+ * inside the workspace. Absolute paths are accepted only when already inside
31
+ * the workspace; everything escaping the cwd is rejected.
32
+ * @param cwd - absolute session workspace root.
33
+ * @param file - the raw path from a tool argument.
34
+ * @returns the absolute, containment-verified path.
35
+ */
36
+ export declare function resolveWorkspaceFile(cwd: string, file: string): string;
37
+ /**
38
+ * Resolve one named directory below a root and verify containment (defense in
39
+ * depth after {@link safeSegment}).
40
+ * @param root - absolute parent root.
41
+ * @param segment - an already validated segment.
42
+ * @returns the absolute, containment-verified directory path.
43
+ */
44
+ export declare function resolveContained(root: string, segment: string): string;
45
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAyBhE;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAOtE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAOtE"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Workspace path resolution and containment for `dsh-industry-research`. All
3
+ * artifacts live under `<cwd>/<industryRoot>/`; every name crossing a tool
4
+ * argument boundary (industry, company, data file) is validated so a crafted
5
+ * value cannot escape the workspace. Both sides of every containment check
6
+ * are resolved before comparison (`path.resolve` returns backslashes on
7
+ * Windows, and comparing against a forward-slash input would always fail).
8
+ * @module dsh-industry-research/paths
9
+ */
10
+ import { isAbsolute, resolve, sep } from 'node:path';
11
+ /** Windows device names that cannot serve as directory segments. */
12
+ const WINDOWS_RESERVED = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])$/iu;
13
+ /** Windows-forbidden filename characters (control characters are checked by code point below). */
14
+ const FORBIDDEN_CHARS = /[<>:"|?*]/u;
15
+ /**
16
+ * Validate one path segment (an industry or company directory name). CJK and
17
+ * other Unicode letters are fine; separators, traversal, control characters,
18
+ * leading/trailing dots/spaces, and Windows device names are rejected.
19
+ * @param label - what the segment names (for the error message).
20
+ * @param value - the raw user/model-supplied name.
21
+ * @returns the trimmed, validated segment.
22
+ */
23
+ export function safeSegment(label, value) {
24
+ const segment = value.trim();
25
+ if (segment.length === 0)
26
+ throw new Error(`${label} must be a non-empty name`);
27
+ if (segment.length > 80)
28
+ throw new Error(`${label} must be at most 80 characters, got ${segment.length}`);
29
+ if (segment.includes('/') || segment.includes('\\')) {
30
+ throw new Error(`${label} must be a single path segment, got ${JSON.stringify(value)}`);
31
+ }
32
+ if (segment === '.' || segment === '..' || segment.includes('..')) {
33
+ throw new Error(`${label} must not contain traversal, got ${JSON.stringify(value)}`);
34
+ }
35
+ if (FORBIDDEN_CHARS.test(segment)) {
36
+ throw new Error(`${label} must not contain Windows-reserved characters, got ${JSON.stringify(value)}`);
37
+ }
38
+ for (const char of segment) {
39
+ if ((char.codePointAt(0) ?? 0) < 0x20) {
40
+ throw new Error(`${label} must not contain control characters, got ${JSON.stringify(value)}`);
41
+ }
42
+ }
43
+ if (segment.startsWith('.') || segment.endsWith('.') || segment.endsWith(' ')) {
44
+ throw new Error(`${label} must not start with '.' or end with '.'/' ', got ${JSON.stringify(value)}`);
45
+ }
46
+ if (WINDOWS_RESERVED.test(segment)) {
47
+ throw new Error(`${label} must not be a Windows device name, got ${JSON.stringify(value)}`);
48
+ }
49
+ return segment;
50
+ }
51
+ /**
52
+ * Resolve `root` against the workspace cwd and return the absolute root.
53
+ * A relative `industryRoot` is workspace-relative; an absolute one is used
54
+ * as-is (deployment choice).
55
+ * @param cwd - absolute session workspace root.
56
+ * @param industryRoot - configured root (relative or absolute).
57
+ * @returns the absolute industry root.
58
+ */
59
+ export function resolveIndustryRoot(cwd, industryRoot) {
60
+ return isAbsolute(industryRoot) ? resolve(industryRoot) : resolve(cwd, industryRoot);
61
+ }
62
+ /**
63
+ * Resolve a user-supplied workspace-relative file path and verify containment
64
+ * inside the workspace. Absolute paths are accepted only when already inside
65
+ * the workspace; everything escaping the cwd is rejected.
66
+ * @param cwd - absolute session workspace root.
67
+ * @param file - the raw path from a tool argument.
68
+ * @returns the absolute, containment-verified path.
69
+ */
70
+ export function resolveWorkspaceFile(cwd, file) {
71
+ const base = resolve(cwd);
72
+ const target = isAbsolute(file) ? resolve(file) : resolve(base, file);
73
+ if (target !== base && !target.startsWith(base + sep)) {
74
+ throw new Error(`path escapes the session workspace: ${JSON.stringify(file)}`);
75
+ }
76
+ return target;
77
+ }
78
+ /**
79
+ * Resolve one named directory below a root and verify containment (defense in
80
+ * depth after {@link safeSegment}).
81
+ * @param root - absolute parent root.
82
+ * @param segment - an already validated segment.
83
+ * @returns the absolute, containment-verified directory path.
84
+ */
85
+ export function resolveContained(root, segment) {
86
+ const base = resolve(root);
87
+ const target = resolve(base, segment);
88
+ if (!target.startsWith(base + sep)) {
89
+ throw new Error(`segment escapes its root: ${JSON.stringify(segment)}`);
90
+ }
91
+ return target;
92
+ }
93
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/paths.ts"],"names":[],"mappings":"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"}